blob: 2346cfc07a8394331ebd6a5253404d350408ed87 [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 Nagarkar1575a042018-10-24 17:54:54 -070020import static android.location.LocationProvider.AVAILABLE;
Soonil Nagarkar94749f72018-11-08 11:46:43 -080021import static android.provider.Settings.Global.LOCATION_DISABLE_STATUS_CALLBACKS;
Maggieaa080f92018-01-04 15:35:11 -080022
Soonil Nagarkar1575a042018-10-24 17:54:54 -070023import static com.android.internal.util.Preconditions.checkState;
24
Wei Wang980b7c22018-12-06 17:53:00 -080025import android.Manifest;
Wyatt Rileycf879db2017-01-12 13:57:38 -080026import android.annotation.NonNull;
Wyatt Riley49097c02018-03-15 09:14:43 -070027import android.annotation.Nullable;
Maggieaa080f92018-01-04 15:35:11 -080028import android.app.ActivityManager;
29import android.app.AppOpsManager;
30import android.app.PendingIntent;
31import android.content.BroadcastReceiver;
32import android.content.ContentResolver;
33import android.content.Context;
34import android.content.Intent;
35import android.content.IntentFilter;
36import android.content.pm.ApplicationInfo;
37import android.content.pm.PackageInfo;
38import android.content.pm.PackageManager;
39import android.content.pm.PackageManager.NameNotFoundException;
40import android.content.pm.PackageManagerInternal;
41import android.content.pm.ResolveInfo;
42import android.content.pm.Signature;
43import android.content.res.Resources;
44import android.database.ContentObserver;
45import android.hardware.location.ActivityRecognitionHardware;
46import android.location.Address;
47import android.location.Criteria;
48import android.location.GeocoderParams;
49import android.location.Geofence;
gomo226b7b72018-12-12 16:49:39 -080050import android.location.GnssMeasurementCorrections;
Maggieaa080f92018-01-04 15:35:11 -080051import android.location.IBatchedLocationCallback;
52import android.location.IGnssMeasurementsListener;
53import android.location.IGnssNavigationMessageListener;
54import android.location.IGnssStatusListener;
Maggieaa080f92018-01-04 15:35:11 -080055import android.location.IGpsGeofenceHardware;
56import android.location.ILocationListener;
57import android.location.ILocationManager;
58import android.location.INetInitiatedListener;
59import android.location.Location;
60import android.location.LocationManager;
Maggieaa080f92018-01-04 15:35:11 -080061import android.location.LocationRequest;
62import android.os.Binder;
63import android.os.Bundle;
64import android.os.Handler;
65import android.os.IBinder;
66import android.os.Looper;
67import android.os.Message;
68import android.os.PowerManager;
69import android.os.Process;
70import android.os.RemoteException;
71import android.os.SystemClock;
72import android.os.UserHandle;
73import android.os.UserManager;
74import android.os.WorkSource;
Narayan Kamath32684dd2018-01-08 17:32:51 +000075import android.os.WorkSource.WorkChain;
Maggieaa080f92018-01-04 15:35:11 -080076import android.provider.Settings;
77import android.text.TextUtils;
Soonil Nagarkar681d7112017-02-23 17:14:16 -080078import android.util.ArrayMap;
Soonil Nagarkar2b565df2017-02-14 13:33:23 -080079import android.util.ArraySet;
Maggieaa080f92018-01-04 15:35:11 -080080import android.util.EventLog;
81import android.util.Log;
82import android.util.Slog;
Yu-Han Yanga4d250e2018-10-02 21:29:20 -070083
destradaaea8a8a62014-06-23 18:19:03 -070084import com.android.internal.content.PackageMonitor;
85import com.android.internal.location.ProviderProperties;
86import com.android.internal.location.ProviderRequest;
87import com.android.internal.os.BackgroundThread;
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -070088import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060089import com.android.internal.util.DumpUtils;
Soonil Nagarkar1575a042018-10-24 17:54:54 -070090import com.android.server.location.AbstractLocationProvider;
destradaaa4fa3b52014-07-09 10:46:39 -070091import com.android.server.location.ActivityRecognitionProxy;
destradaaea8a8a62014-06-23 18:19:03 -070092import com.android.server.location.GeocoderProxy;
93import com.android.server.location.GeofenceManager;
94import com.android.server.location.GeofenceProxy;
Yu-Han Yang3557cc72018-03-21 12:48:36 -070095import com.android.server.location.GnssBatchingProvider;
Lifu Tang818aa2c2016-02-01 01:52:00 -080096import com.android.server.location.GnssLocationProvider;
97import com.android.server.location.GnssMeasurementsProvider;
98import com.android.server.location.GnssNavigationMessageProvider;
Anil Admal75b9fd62018-11-28 11:22:50 -080099import com.android.server.location.GnssStatusListenerHelper;
destradaaea8a8a62014-06-23 18:19:03 -0700100import com.android.server.location.LocationBlacklist;
101import com.android.server.location.LocationFudger;
destradaaea8a8a62014-06-23 18:19:03 -0700102import com.android.server.location.LocationProviderProxy;
103import com.android.server.location.LocationRequestStatistics;
104import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
105import com.android.server.location.LocationRequestStatistics.PackageStatistics;
106import com.android.server.location.MockProvider;
107import com.android.server.location.PassiveProvider;
Yu-Han Yanga4d250e2018-10-02 21:29:20 -0700108
Mike Lockwood43e33f22010-03-26 10:41:48 -0400109import java.io.FileDescriptor;
110import java.io.PrintWriter;
111import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700112import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400113import java.util.HashMap;
114import java.util.HashSet;
115import java.util.List;
116import java.util.Map;
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800117import java.util.Map.Entry;
Wyatt Rileycf879db2017-01-12 13:57:38 -0800118import java.util.NoSuchElementException;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400119import java.util.Set;
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;
Mike Lockwood275555c2009-05-01 11:30:34 -0400140 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700141 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
142
143 private static final String NETWORK_LOCATION_SERVICE_ACTION =
Stan Chesnutt39062dd2013-07-22 14:33:30 -0700144 "com.android.location.service.v3.NetworkLocationProvider";
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700145 private static final String FUSED_LOCATION_SERVICE_ACTION =
146 "com.android.location.service.FusedLocationProvider";
147
148 private static final int MSG_LOCATION_CHANGED = 1;
149
David Christie1b9b7b12013-04-15 15:31:11 -0700150 private static final long NANOS_PER_MILLI = 1000000L;
151
David Christie0b837452013-07-29 16:02:13 -0700152 // The maximum interval a location request can have and still be considered "high power".
153 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
154
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700155 private static final int FOREGROUND_IMPORTANCE_CUTOFF
gomo48f1a642017-11-10 20:35:46 -0800156 = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700157
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800158 // default background throttling interval if not overriden in settings
Soonil Nagarkarde6780a2017-02-07 10:39:41 -0800159 private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800160
Wei Wangdd070f22018-06-21 11:29:40 -0700161 // Default value for maximum age of last location returned to applications with foreground-only
162 // location permissions.
163 private static final long DEFAULT_LAST_LOCATION_MAX_AGE_MS = 20 * 60 * 1000;
164
Nick Pellyf1be6862012-05-15 10:53:42 -0700165 // Location Providers may sometimes deliver location updates
166 // slightly faster that requested - provide grace period so
167 // we don't unnecessarily filter events that are otherwise on
168 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700170
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700171 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
172
173 private final Context mContext;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800174 private final AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700175
176 // used internally for synchronization
177 private final Object mLock = new Object();
178
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700179 // --- fields below are final after systemRunning() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700180 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700181 private GeofenceManager mGeofenceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700182 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700183 private PowerManager mPowerManager;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800184 private ActivityManager mActivityManager;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700185 private UserManager mUserManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700186 private GeocoderProxy mGeocodeProvider;
Anil Admal75b9fd62018-11-28 11:22:50 -0800187 private GnssStatusListenerHelper mGnssStatusProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700188 private INetInitiatedListener mNetInitiatedListener;
189 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700190 private PassiveProvider mPassiveProvider; // track passive provider for special cases
191 private LocationBlacklist mBlacklist;
Lifu Tang818aa2c2016-02-01 01:52:00 -0800192 private GnssMeasurementsProvider mGnssMeasurementsProvider;
193 private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
Wei Wang980b7c22018-12-06 17:53:00 -0800194 private String mLocationControllerExtraPackage;
195 private boolean mLocationControllerExtraPackageEnabled;
Wei Liu5241a4c2015-05-11 14:00:36 -0700196 private IGpsGeofenceHardware mGpsGeofenceProxy;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700197
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700198 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700200 // Mock (test) providers
201 private final HashMap<String, MockProvider> mMockProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800202 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700204 // all receivers
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800205 private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700207 // currently installed providers (with mocks replacing real providers)
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700208 private final ArrayList<LocationProvider> mProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800209 new ArrayList<>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400210
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700211 // real providers, saved here when mocked out
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700212 private final HashMap<String, LocationProvider> mRealProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800213 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700215 // mapping from provider name to provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700216 private final HashMap<String, LocationProvider> mProvidersByName =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800217 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700219 // mapping from provider name to all its UpdateRecords
220 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800221 new HashMap<>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700222
David Christie2ff96af2014-01-30 16:09:37 -0800223 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
224
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700225 // mapping from provider name to last known location
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800226 private final HashMap<String, Location> mLastLocation = new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227
David Christie1b9b7b12013-04-15 15:31:11 -0700228 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
229 // locations stored here are not fudged for coarse permissions.
230 private final HashMap<String, Location> mLastLocationCoarseInterval =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800231 new HashMap<>();
David Christie1b9b7b12013-04-15 15:31:11 -0700232
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800233 // all providers that operate over proxy, for authorizing incoming location and whitelisting
234 // throttling
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700235 private final ArrayList<LocationProviderProxy> mProxyProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800236 new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237
Soonil Nagarkar2b565df2017-02-14 13:33:23 -0800238 private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800239
Wyatt Riley11cc7492018-01-17 08:48:27 -0800240 private final ArrayMap<IBinder, Identity> mGnssMeasurementsListeners = new ArrayMap<>();
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800241
Wyatt Riley11cc7492018-01-17 08:48:27 -0800242 private final ArrayMap<IBinder, Identity>
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800243 mGnssNavigationMessageListeners = new ArrayMap<>();
244
Victoria Lease38389b62012-09-30 11:44:22 -0700245 // current active user on the device - other users are denied location data
Xiaohui Chena4490622015-09-22 15:29:31 -0700246 private int mCurrentUserId = UserHandle.USER_SYSTEM;
gomo48f1a642017-11-10 20:35:46 -0800247 private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
Victoria Lease38389b62012-09-30 11:44:22 -0700248
Wei Wangdd070f22018-06-21 11:29:40 -0700249 // Maximum age of last location returned to clients with foreground-only location permissions.
250 private long mLastLocationMaxAgeMs;
251
Lifu Tang9363b942016-02-16 18:07:00 -0800252 private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
Lifu Tang82f893d2016-01-21 18:15:33 -0800253
Siddharth Raybb608c82017-03-16 11:33:34 -0700254 private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
Wyatt Rileyaa420d52017-07-03 15:14:42 -0700255
Yu-Han Yang3557cc72018-03-21 12:48:36 -0700256 private GnssBatchingProvider mGnssBatchingProvider;
Wyatt Rileycf879db2017-01-12 13:57:38 -0800257 private IBatchedLocationCallback mGnssBatchingCallback;
258 private LinkedCallback mGnssBatchingDeathCallback;
259 private boolean mGnssBatchingInProgress = false;
260
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700261 public LocationManagerService(Context context) {
262 super();
263 mContext = context;
gomo48f1a642017-11-10 20:35:46 -0800264 mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800265
Svet Ganovadc1cf42015-06-15 16:36:24 -0700266 // Let the package manager query which are the default location
267 // providers as they get certain permissions granted by default.
268 PackageManagerInternal packageManagerInternal = LocalServices.getService(
269 PackageManagerInternal.class);
270 packageManagerInternal.setLocationPackagesProvider(
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700271 userId -> mContext.getResources().getStringArray(
272 com.android.internal.R.array.config_locationProviderPackageNames));
Svet Ganovadc1cf42015-06-15 16:36:24 -0700273
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700274 if (D) Log.d(TAG, "Constructed");
275
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700276 // most startup is deferred until systemRunning()
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700277 }
278
Svetoslav Ganova0027152013-06-25 14:59:53 -0700279 public void systemRunning() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700280 synchronized (mLock) {
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700281 if (D) Log.d(TAG, "systemRunning()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700282
Victoria Lease5cd731a2012-12-19 15:04:21 -0800283 // fetch package manager
284 mPackageManager = mContext.getPackageManager();
285
Victoria Lease0aa28602013-05-29 15:28:26 -0700286 // fetch power manager
287 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800288
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800289 // fetch activity manager
290 mActivityManager
291 = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
292
Victoria Lease5cd731a2012-12-19 15:04:21 -0800293 // prepare worker thread
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700294 mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
Victoria Lease5cd731a2012-12-19 15:04:21 -0800295
296 // prepare mLocationHandler's dependents
297 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
298 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
299 mBlacklist.init();
300 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
301
Dianne Hackbornc2293022013-02-06 23:14:49 -0800302 // Monitor for app ops mode changes.
Dianne Hackborn9bb0ee92013-09-22 12:31:38 -0700303 AppOpsManager.OnOpChangedListener callback
304 = new AppOpsManager.OnOpChangedInternalListener() {
305 public void onOpChanged(int op, String packageName) {
Soonil Nagarkarde3051c2018-12-18 08:42:19 -0800306 mLocationHandler.post(() -> {
307 synchronized (mLock) {
308 for (Receiver receiver : mReceivers.values()) {
309 receiver.updateMonitoring(true);
310 }
311 applyAllProviderRequirementsLocked();
312 }
313 });
Dianne Hackbornc2293022013-02-06 23:14:49 -0800314 }
315 };
Wei Wangdd070f22018-06-21 11:29:40 -0700316 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null,
317 AppOpsManager.WATCH_FOREGROUND_CHANGES, callback);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800318
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700319 PackageManager.OnPermissionsChangedListener permissionListener = uid -> {
320 synchronized (mLock) {
321 applyAllProviderRequirementsLocked();
David Christieb870dbf2015-06-22 12:42:53 -0700322 }
323 };
324 mPackageManager.addOnPermissionsChangeListener(permissionListener);
325
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800326 // listen for background/foreground changes
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700327 ActivityManager.OnUidImportanceListener uidImportanceListener =
328 (uid, importance) -> mLocationHandler.post(
329 () -> onUidImportanceChanged(uid, importance));
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800330 mActivityManager.addOnUidImportanceListener(uidImportanceListener,
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700331 FOREGROUND_IMPORTANCE_CUTOFF);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800332
Amith Yamasanib27528d2014-06-05 15:02:10 -0700333 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
334 updateUserProfiles(mCurrentUserId);
335
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800336 updateBackgroundThrottlingWhitelistLocked();
Wei Wangdd070f22018-06-21 11:29:40 -0700337 updateLastLocationMaxAgeLocked();
Soonil Nagarkar2b565df2017-02-14 13:33:23 -0800338
Victoria Lease5cd731a2012-12-19 15:04:21 -0800339 // prepare providers
340 loadProvidersLocked();
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700341 updateProvidersSettingsLocked();
342 for (LocationProvider provider : mProviders) {
343 applyRequirementsLocked(provider.getName());
344 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800345 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700346
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700347 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700348 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700349 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700350 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800351 @Override
352 public void onChange(boolean selfChange) {
353 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700354 updateProvidersSettingsLocked();
Victoria Lease5cd731a2012-12-19 15:04:21 -0800355 }
356 }
357 }, UserHandle.USER_ALL);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800358 mContext.getContentResolver().registerContentObserver(
359 Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS),
360 true,
361 new ContentObserver(mLocationHandler) {
362 @Override
363 public void onChange(boolean selfChange) {
364 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700365 for (LocationProvider provider : mProviders) {
366 applyRequirementsLocked(provider.getName());
367 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800368 }
369 }
370 }, UserHandle.USER_ALL);
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800371 mContext.getContentResolver().registerContentObserver(
Wei Wangdd070f22018-06-21 11:29:40 -0700372 Settings.Global.getUriFor(Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS),
373 true,
374 new ContentObserver(mLocationHandler) {
375 @Override
376 public void onChange(boolean selfChange) {
377 synchronized (mLock) {
378 updateLastLocationMaxAgeLocked();
379 }
380 }
381 }
382 );
383 mContext.getContentResolver().registerContentObserver(
gomo48f1a642017-11-10 20:35:46 -0800384 Settings.Global.getUriFor(
385 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
386 true,
387 new ContentObserver(mLocationHandler) {
388 @Override
389 public void onChange(boolean selfChange) {
390 synchronized (mLock) {
391 updateBackgroundThrottlingWhitelistLocked();
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700392 for (LocationProvider provider : mProviders) {
393 applyRequirementsLocked(provider.getName());
394 }
gomo48f1a642017-11-10 20:35:46 -0800395 }
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800396 }
gomo48f1a642017-11-10 20:35:46 -0800397 }, UserHandle.USER_ALL);
Wei Wangdd070f22018-06-21 11:29:40 -0700398
Victoria Lease5cd731a2012-12-19 15:04:21 -0800399 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700400
Victoria Lease38389b62012-09-30 11:44:22 -0700401 // listen for user change
402 IntentFilter intentFilter = new IntentFilter();
403 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700404 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
405 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
Victoria Lease38389b62012-09-30 11:44:22 -0700406
407 mContext.registerReceiverAsUser(new BroadcastReceiver() {
408 @Override
409 public void onReceive(Context context, Intent intent) {
410 String action = intent.getAction();
411 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
412 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
Amith Yamasanib27528d2014-06-05 15:02:10 -0700413 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
414 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
415 updateUserProfiles(mCurrentUserId);
Victoria Lease38389b62012-09-30 11:44:22 -0700416 }
417 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800418 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700419 }
420
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700421 private void onUidImportanceChanged(int uid, int importance) {
422 boolean foreground = isImportanceForeground(importance);
423 HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
424 synchronized (mLock) {
425 for (Entry<String, ArrayList<UpdateRecord>> entry
gomo48f1a642017-11-10 20:35:46 -0800426 : mRecordsByProvider.entrySet()) {
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700427 String provider = entry.getKey();
428 for (UpdateRecord record : entry.getValue()) {
429 if (record.mReceiver.mIdentity.mUid == uid
gomo48f1a642017-11-10 20:35:46 -0800430 && record.mIsForegroundUid != foreground) {
431 if (D) {
432 Log.d(TAG, "request from uid " + uid + " is now "
433 + (foreground ? "foreground" : "background)"));
434 }
Wyatt Rileyf7075e02018-04-12 17:54:26 -0700435 record.updateForeground(foreground);
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700436
437 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
438 affectedProviders.add(provider);
439 }
440 }
441 }
442 }
443 for (String provider : affectedProviders) {
444 applyRequirementsLocked(provider);
445 }
446
Wyatt Riley11cc7492018-01-17 08:48:27 -0800447 for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
Anil Admal75b9fd62018-11-28 11:22:50 -0800448 Identity callerIdentity = entry.getValue();
449 if (callerIdentity.mUid == uid) {
gomo48f1a642017-11-10 20:35:46 -0800450 if (D) {
451 Log.d(TAG, "gnss measurements listener from uid " + uid
452 + " is now " + (foreground ? "foreground" : "background)"));
453 }
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700454 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800455 mGnssMeasurementsProvider.addListener(
Anil Admal75b9fd62018-11-28 11:22:50 -0800456 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
457 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700458 } else {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800459 mGnssMeasurementsProvider.removeListener(
460 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700461 }
462 }
463 }
464
Wyatt Riley11cc7492018-01-17 08:48:27 -0800465 for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
Anil Admal75b9fd62018-11-28 11:22:50 -0800466 Identity callerIdentity = entry.getValue();
467 if (callerIdentity.mUid == uid) {
gomo48f1a642017-11-10 20:35:46 -0800468 if (D) {
469 Log.d(TAG, "gnss navigation message listener from uid "
470 + uid + " is now "
471 + (foreground ? "foreground" : "background)"));
472 }
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700473 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800474 mGnssNavigationMessageProvider.addListener(
Anil Admal75b9fd62018-11-28 11:22:50 -0800475 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
476 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700477 } else {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800478 mGnssNavigationMessageProvider.removeListener(
479 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700480 }
481 }
482 }
Anil Admal75b9fd62018-11-28 11:22:50 -0800483
484 // TODO(b/120449926): The GNSS status listeners should be handled similar to the above.
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700485 }
486 }
487
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800488 private static boolean isImportanceForeground(int importance) {
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700489 return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800490 }
491
Amith Yamasanib27528d2014-06-05 15:02:10 -0700492 /**
493 * Makes a list of userids that are related to the current user. This is
494 * relevant when using managed profiles. Otherwise the list only contains
495 * the current user.
496 *
497 * @param currentUserId the current user, who might have an alter-ego.
498 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700499 private void updateUserProfiles(int currentUserId) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700500 int[] profileIds = mUserManager.getProfileIdsWithDisabled(currentUserId);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700501 synchronized (mLock) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700502 mCurrentUserProfiles = profileIds;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700503 }
504 }
505
506 /**
507 * Checks if the specified userId matches any of the current foreground
508 * users stored in mCurrentUserProfiles.
509 */
510 private boolean isCurrentProfile(int userId) {
511 synchronized (mLock) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700512 return ArrayUtils.contains(mCurrentUserProfiles, userId);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700513 }
514 }
515
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700516 private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) {
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500517 PackageManager pm = mContext.getPackageManager();
518 String systemPackageName = mContext.getPackageName();
519 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
520
521 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
522 new Intent(FUSED_LOCATION_SERVICE_ACTION),
523 PackageManager.GET_META_DATA, mCurrentUserId);
524 for (ResolveInfo rInfo : rInfos) {
525 String packageName = rInfo.serviceInfo.packageName;
526
527 // Check that the signature is in the list of supported sigs. If it's not in
528 // this list the standard provider binding logic won't bind to it.
529 try {
530 PackageInfo pInfo;
531 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
532 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
533 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
534 ", but has wrong signature, ignoring");
535 continue;
536 }
537 } catch (NameNotFoundException e) {
538 Log.e(TAG, "missing package: " + packageName);
539 continue;
540 }
541
542 // Get the version info
543 if (rInfo.serviceInfo.metaData == null) {
544 Log.w(TAG, "Found fused provider without metadata: " + packageName);
545 continue;
546 }
547
548 int version = rInfo.serviceInfo.metaData.getInt(
549 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
550 if (version == 0) {
551 // This should be the fallback fused location provider.
552
553 // Make sure it's in the system partition.
554 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
555 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
556 continue;
557 }
558
559 // Check that the fallback is signed the same as the OS
560 // as a proxy for coreApp="true"
561 if (pm.checkSignatures(systemPackageName, packageName)
562 != PackageManager.SIGNATURE_MATCH) {
gomo48f1a642017-11-10 20:35:46 -0800563 if (D) {
564 Log.d(TAG, "Fallback candidate not signed the same as system: "
565 + packageName);
566 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500567 continue;
568 }
569
570 // Found a valid fallback.
571 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
572 return;
573 } else {
574 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
575 }
576 }
577
578 throw new IllegalStateException("Unable to find a fused location provider that is in the "
579 + "system partition with version 0 and signed with the platform certificate. "
580 + "Such a package is needed to provide a default fused location provider in the "
581 + "event that no other fused location provider has been installed or is currently "
582 + "available. For example, coreOnly boot mode when decrypting the data "
583 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
584 }
585
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700586 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700587 // create a passive location provider, which is always enabled
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700588 LocationProvider passiveProviderManager = new LocationProvider(
589 LocationManager.PASSIVE_PROVIDER);
590 PassiveProvider passiveProvider = new PassiveProvider(passiveProviderManager);
591
592 addProviderLocked(passiveProviderManager);
Victoria Lease5c24fd02012-10-01 11:00:50 -0700593 mPassiveProvider = passiveProvider;
594
Lifu Tang30f95a72016-01-07 23:20:38 -0800595 if (GnssLocationProvider.isSupported()) {
Wei Liu5241a4c2015-05-11 14:00:36 -0700596 // Create a gps location provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700597 LocationProvider gnssProviderManager = new LocationProvider(
598 LocationManager.GPS_PROVIDER);
599 GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext,
600 gnssProviderManager,
Wei Liu5241a4c2015-05-11 14:00:36 -0700601 mLocationHandler.getLooper());
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700602
Lifu Tang9363b942016-02-16 18:07:00 -0800603 mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
Wyatt Rileycf879db2017-01-12 13:57:38 -0800604 mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
Siddharth Raybb608c82017-03-16 11:33:34 -0700605 mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800606 mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
607 mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700608 addProviderLocked(gnssProviderManager);
609 mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProviderManager);
Lifu Tang818aa2c2016-02-01 01:52:00 -0800610 mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
611 mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800612 mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700613 }
614
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700615 /*
616 Load package name(s) containing location provider support.
617 These packages can contain services implementing location providers:
618 Geocoder Provider, Network Location Provider, and
619 Fused Location Provider. They will each be searched for
620 service components implementing these providers.
621 The location framework also has support for installation
622 of new location providers at run-time. The new package does not
623 have to be explicitly listed here, however it must have a signature
624 that matches the signature of at least one package on this list.
625 */
626 Resources resources = mContext.getResources();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500627 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700628 com.android.internal.R.array.config_locationProviderPackageNames);
gomo48f1a642017-11-10 20:35:46 -0800629 if (D) {
630 Log.d(TAG, "certificates for location providers pulled from: " +
631 Arrays.toString(pkgs));
632 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500633
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700634 ensureFallbackFusedProviderPresentLocked(pkgs);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700635
636 // bind to network provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700637
638 LocationProvider networkProviderManager = new LocationProvider(
639 LocationManager.NETWORK_PROVIDER);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700640 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
641 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700642 networkProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700643 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700644 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
645 com.android.internal.R.string.config_networkLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700646 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700647 if (networkProvider != null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700648 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProviderManager);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700649 mProxyProviders.add(networkProvider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700650 addProviderLocked(networkProviderManager);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700651 } else {
gomo48f1a642017-11-10 20:35:46 -0800652 Slog.w(TAG, "no network location provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700653 }
654
655 // bind to fused provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700656 LocationProvider fusedProviderManager = new LocationProvider(
657 LocationManager.FUSED_PROVIDER);
658 LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700659 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700660 fusedProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700661 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700662 com.android.internal.R.bool.config_enableFusedLocationOverlay,
663 com.android.internal.R.string.config_fusedLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700664 com.android.internal.R.array.config_locationProviderPackageNames);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700665 if (fusedProvider != null) {
666 addProviderLocked(fusedProviderManager);
667 mProxyProviders.add(fusedProvider);
668 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedProviderManager);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700669 } else {
670 Slog.e(TAG, "no fused location provider found",
671 new IllegalStateException("Location service needs a fused location provider"));
672 }
673
674 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700675 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
676 com.android.internal.R.bool.config_enableGeocoderOverlay,
677 com.android.internal.R.string.config_geocoderProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700678 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700679 if (mGeocodeProvider == null) {
gomo48f1a642017-11-10 20:35:46 -0800680 Slog.e(TAG, "no geocoder provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700681 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700682
destradaaf9a274c2014-07-25 15:11:56 -0700683 // bind to geofence provider
684 GeofenceProxy provider = GeofenceProxy.createAndBind(
gomo48f1a642017-11-10 20:35:46 -0800685 mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
destradaaf9a274c2014-07-25 15:11:56 -0700686 com.android.internal.R.string.config_geofenceProviderPackageName,
687 com.android.internal.R.array.config_locationProviderPackageNames,
Wei Liu5241a4c2015-05-11 14:00:36 -0700688 mGpsGeofenceProxy,
Jiyong Park4cc3a1c2018-03-08 16:43:07 +0900689 null);
destradaaf9a274c2014-07-25 15:11:56 -0700690 if (provider == null) {
gomo48f1a642017-11-10 20:35:46 -0800691 Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
destradaa0682809a2013-08-12 18:50:30 -0700692 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900693
destradaa6e2fe752015-06-23 17:25:53 -0700694 // bind to hardware activity recognition
695 boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported();
696 ActivityRecognitionHardware activityRecognitionHardware = null;
697 if (activityRecognitionHardwareIsSupported) {
698 activityRecognitionHardware = ActivityRecognitionHardware.getInstance(mContext);
destradaaa4fa3b52014-07-09 10:46:39 -0700699 } else {
destradaa6b4893a2016-05-03 15:33:43 -0700700 Slog.d(TAG, "Hardware Activity-Recognition not supported.");
destradaaa4fa3b52014-07-09 10:46:39 -0700701 }
destradaa6e2fe752015-06-23 17:25:53 -0700702 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
703 mContext,
destradaa6e2fe752015-06-23 17:25:53 -0700704 activityRecognitionHardwareIsSupported,
705 activityRecognitionHardware,
706 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
707 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
708 com.android.internal.R.array.config_locationProviderPackageNames);
709 if (proxy == null) {
destradaa6b4893a2016-05-03 15:33:43 -0700710 Slog.d(TAG, "Unable to bind ActivityRecognitionProxy.");
destradaa6e2fe752015-06-23 17:25:53 -0700711 }
destradaaa4fa3b52014-07-09 10:46:39 -0700712
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900713 String[] testProviderStrings = resources.getStringArray(
714 com.android.internal.R.array.config_testLocationProviders);
715 for (String testProviderString : testProviderStrings) {
716 String fragments[] = testProviderString.split(",");
717 String name = fragments[0].trim();
718 if (mProvidersByName.get(name) != null) {
719 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
720 }
721 ProviderProperties properties = new ProviderProperties(
722 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
723 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
724 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
725 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
726 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
727 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
728 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
729 Integer.parseInt(fragments[8]) /* powerRequirement */,
730 Integer.parseInt(fragments[9]) /* accuracy */);
731 addTestProviderLocked(name, properties);
732 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700733 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700734
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800735 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700736 * Called when the device's active user changes.
gomo48f1a642017-11-10 20:35:46 -0800737 *
Victoria Lease38389b62012-09-30 11:44:22 -0700738 * @param userId the new active user's UserId
739 */
740 private void switchUser(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800741 if (mCurrentUserId == userId) {
742 return;
743 }
Victoria Lease83762d22012-10-03 13:51:17 -0700744 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800745 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700746 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700747 mLastLocation.clear();
David Christie1b9b7b12013-04-15 15:31:11 -0700748 mLastLocationCoarseInterval.clear();
Amith Yamasanib27528d2014-06-05 15:02:10 -0700749 updateUserProfiles(userId);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700750 updateProvidersSettingsLocked();
751 mCurrentUserId = userId;
Victoria Lease38389b62012-09-30 11:44:22 -0700752 }
753 }
754
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800755 private static final class Identity {
756 final int mUid;
757 final int mPid;
758 final String mPackageName;
759
760 Identity(int uid, int pid, String packageName) {
761 mUid = uid;
762 mPid = pid;
763 mPackageName = packageName;
764 }
765 }
766
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700767 private class LocationProvider implements AbstractLocationProvider.LocationProviderManager {
768
769 private final String mName;
770 private AbstractLocationProvider mProvider;
771
772 // whether the provider is enabled in location settings
773 private boolean mSettingsEnabled;
774
775 // whether the provider considers itself enabled
776 private volatile boolean mEnabled;
777
778 @Nullable
779 private volatile ProviderProperties mProperties;
780
781 private LocationProvider(String name) {
782 mName = name;
783 // TODO: initialize settings enabled?
784 }
785
786 @Override
787 public void onAttachProvider(AbstractLocationProvider provider, boolean initiallyEnabled) {
788 checkState(mProvider == null);
789
790 // the provider is not yet fully constructed at this point, so we may not do anything
791 // except save a reference for later use here. do not call any provider methods.
792 mProvider = provider;
793 mEnabled = initiallyEnabled;
794 mProperties = null;
795 }
796
797 public String getName() {
798 return mName;
799 }
800
801 public boolean isEnabled() {
802 return mSettingsEnabled && mEnabled;
803 }
804
805 @Nullable
806 public ProviderProperties getProperties() {
807 return mProperties;
808 }
809
810 public void setRequest(ProviderRequest request, WorkSource workSource) {
811 mProvider.setRequest(request, workSource);
812 }
813
814 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
815 pw.println(mName + " provider:");
816 pw.println(" setting=" + mSettingsEnabled);
817 pw.println(" enabled=" + mEnabled);
818 pw.println(" properties=" + mProperties);
819 mProvider.dump(fd, pw, args);
820 }
821
822 public long getStatusUpdateTime() {
823 return mProvider.getStatusUpdateTime();
824 }
825
826 public int getStatus(Bundle extras) {
827 return mProvider.getStatus(extras);
828 }
829
830 public void sendExtraCommand(String command, Bundle extras) {
831 mProvider.sendExtraCommand(command, extras);
832 }
833
834 // called from any thread
835 @Override
836 public void onReportLocation(Location location) {
837 runOnHandler(() -> LocationManagerService.this.reportLocation(location,
838 mProvider == mPassiveProvider));
839 }
840
841 // called from any thread
842 @Override
843 public void onReportLocation(List<Location> locations) {
844 runOnHandler(() -> LocationManagerService.this.reportLocationBatch(locations));
845 }
846
847 // called from any thread
848 @Override
849 public void onSetEnabled(boolean enabled) {
850 runOnHandler(() -> {
851 if (enabled == mEnabled) {
852 return;
853 }
854
855 mEnabled = enabled;
856
857 if (!mSettingsEnabled) {
858 // this provider was disabled in settings anyways, so a change to it's own
859 // enabled status won't have any affect.
860 return;
861 }
862
863 // traditionally clients can listen for changes to the LOCATION_PROVIDERS_ALLOWED
864 // setting to detect when providers are enabled or disabled (even though they aren't
865 // supposed to). to continue to support this we must force a change to this setting.
866 // we use the fused provider because this is forced to be always enabled in settings
867 // anyways, and so won't have any visible effect beyond triggering content observers
868 Settings.Secure.putStringForUser(mContext.getContentResolver(),
869 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
870 "+" + LocationManager.FUSED_PROVIDER, mCurrentUserId);
871 Settings.Secure.putStringForUser(mContext.getContentResolver(),
872 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
873 "-" + LocationManager.FUSED_PROVIDER, mCurrentUserId);
874
875 synchronized (mLock) {
876 if (!enabled) {
877 // If any provider has been disabled, clear all last locations for all
878 // providers. This is to be on the safe side in case a provider has location
879 // derived from this disabled provider.
880 mLastLocation.clear();
881 mLastLocationCoarseInterval.clear();
882 }
883
884 updateProviderListenersLocked(mName);
885 }
886
887 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
888 UserHandle.ALL);
889 });
890 }
891
892 @Override
893 public void onSetProperties(ProviderProperties properties) {
894 runOnHandler(() -> mProperties = properties);
895 }
896
897 private void setSettingsEnabled(boolean enabled) {
898 synchronized (mLock) {
899 if (mSettingsEnabled == enabled) {
900 return;
901 }
902
903 mSettingsEnabled = enabled;
904 if (!mSettingsEnabled) {
905 // if any provider has been disabled, clear all last locations for all
906 // providers. this is to be on the safe side in case a provider has location
907 // derived from this disabled provider.
908 mLastLocation.clear();
909 mLastLocationCoarseInterval.clear();
910 updateProviderListenersLocked(mName);
911 } else if (mEnabled) {
912 updateProviderListenersLocked(mName);
913 }
914 }
915 }
916
917 private void runOnHandler(Runnable runnable) {
918 if (Looper.myLooper() == mLocationHandler.getLooper()) {
919 runnable.run();
920 } else {
921 mLocationHandler.post(runnable);
922 }
923 }
924 }
925
Victoria Lease38389b62012-09-30 11:44:22 -0700926 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
928 * location updates.
929 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700930 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Yu-Han Yang24189822018-07-11 15:24:11 -0700931 private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800932 final Identity mIdentity;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700933 private final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700934
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700935 private final ILocationListener mListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -0700937 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700938 private final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
939 private final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700940
gomo48f1a642017-11-10 20:35:46 -0800941 final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700942
David Christie0b837452013-07-29 16:02:13 -0700943 // True if app ops has started monitoring this receiver for locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700944 private boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -0700945 // True if app ops has started monitoring this receiver for high power (gps) locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700946 private boolean mOpHighPowerMonitoring;
947 private int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -0700948 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700950 private Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -0700951 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700954 if (listener != null) {
955 mKey = listener.asBinder();
956 } else {
957 mKey = intent;
958 }
Victoria Lease37425c32012-10-16 16:08:48 -0700959 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800960 mIdentity = new Identity(uid, pid, packageName);
Narayan Kamath32684dd2018-01-08 17:32:51 +0000961 if (workSource != null && workSource.isEmpty()) {
David Christie82edc9b2013-07-19 11:31:42 -0700962 workSource = null;
963 }
964 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -0700965 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -0700966
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700967 updateMonitoring(true);
968
Victoria Lease0aa28602013-05-29 15:28:26 -0700969 // construct/configure wakelock
970 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -0700971 if (workSource == null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800972 workSource = new WorkSource(mIdentity.mUid, mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -0700973 }
974 mWakeLock.setWorkSource(workSource);
Yu-Han Yang24189822018-07-11 15:24:11 -0700975
976 // For a non-reference counted wakelock, each acquire will reset the timeout, and we
977 // only need to release it once.
978 mWakeLock.setReferenceCounted(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 }
980
981 @Override
982 public boolean equals(Object otherObj) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800983 return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 }
985
986 @Override
987 public int hashCode() {
988 return mKey.hashCode();
989 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400990
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 @Override
992 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700993 StringBuilder s = new StringBuilder();
994 s.append("Reciever[");
995 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700997 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700999 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001001 for (String p : mUpdateRecords.keySet()) {
1002 s.append(" ").append(mUpdateRecords.get(p).toString());
1003 }
Wei Wangdd070f22018-06-21 11:29:40 -07001004 s.append(" monitoring location: ").append(mOpMonitoring);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001005 s.append("]");
1006 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 }
1008
David Christie15b31912013-08-13 15:54:32 -07001009 /**
1010 * Update AppOp monitoring for this receiver.
1011 *
1012 * @param allow If true receiver is currently active, if false it's been removed.
1013 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001014 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -07001015 if (mHideFromAppOps) {
1016 return;
1017 }
1018
David Christie15b31912013-08-13 15:54:32 -07001019 boolean requestingLocation = false;
1020 boolean requestingHighPowerLocation = false;
1021 if (allow) {
1022 // See if receiver has any enabled update records. Also note if any update records
1023 // are high power (has a high power provider with an interval under a threshold).
1024 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001025 if (isAllowedByUserSettingsLockedForUser(updateRecord.mProvider,
1026 mCurrentUserId)) {
David Christie15b31912013-08-13 15:54:32 -07001027 requestingLocation = true;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001028 LocationManagerService.LocationProvider locationProvider
David Christie2ff96af2014-01-30 16:09:37 -08001029 = mProvidersByName.get(updateRecord.mProvider);
David Christie15b31912013-08-13 15:54:32 -07001030 ProviderProperties properties = locationProvider != null
1031 ? locationProvider.getProperties() : null;
1032 if (properties != null
1033 && properties.mPowerRequirement == Criteria.POWER_HIGH
1034 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
1035 requestingHighPowerLocation = true;
1036 break;
1037 }
1038 }
1039 }
1040 }
1041
David Christie0b837452013-07-29 16:02:13 -07001042 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -07001043 mOpMonitoring = updateMonitoring(
1044 requestingLocation,
1045 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001046 AppOpsManager.OP_MONITOR_LOCATION);
1047
1048 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -07001049 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -07001050 mOpHighPowerMonitoring = updateMonitoring(
1051 requestingHighPowerLocation,
1052 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001053 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -07001054 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -07001055 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -07001056 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
1057 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1058 }
David Christie0b837452013-07-29 16:02:13 -07001059 }
1060
1061 /**
1062 * Update AppOps monitoring for a single location request and op type.
1063 *
gomo48f1a642017-11-10 20:35:46 -08001064 * @param allowMonitoring True if monitoring is allowed for this request/op.
David Christie0b837452013-07-29 16:02:13 -07001065 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
gomo48f1a642017-11-10 20:35:46 -08001066 * @param op AppOps code for the op to update.
David Christie0b837452013-07-29 16:02:13 -07001067 * @return True if monitoring is on for this request/op after updating.
1068 */
1069 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
1070 int op) {
1071 if (!currentlyMonitoring) {
1072 if (allowMonitoring) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001073 return mAppOps.startOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001074 == AppOpsManager.MODE_ALLOWED;
1075 }
1076 } else {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001077 if (!allowMonitoring
Wei Wangdd070f22018-06-21 11:29:40 -07001078 || mAppOps.noteOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001079 != AppOpsManager.MODE_ALLOWED) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001080 mAppOps.finishOp(op, mIdentity.mUid, mIdentity.mPackageName);
David Christie0b837452013-07-29 16:02:13 -07001081 return false;
1082 }
1083 }
1084
1085 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001086 }
1087
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088 public boolean isListener() {
1089 return mListener != null;
1090 }
1091
1092 public boolean isPendingIntent() {
1093 return mPendingIntent != null;
1094 }
1095
1096 public ILocationListener getListener() {
1097 if (mListener != null) {
1098 return mListener;
1099 }
1100 throw new IllegalStateException("Request for non-existent listener");
1101 }
1102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
1104 if (mListener != null) {
1105 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001106 synchronized (this) {
1107 // synchronize to ensure incrementPendingBroadcastsLocked()
1108 // is called before decrementPendingBroadcasts()
1109 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -07001110 // call this after broadcasting so we do not increment
1111 // if we throw an exeption.
1112 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001113 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 } catch (RemoteException e) {
1115 return false;
1116 }
1117 } else {
1118 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -08001119 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
1121 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001122 synchronized (this) {
1123 // synchronize to ensure incrementPendingBroadcastsLocked()
1124 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001125 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001126 getResolutionPermission(mAllowedResolutionLevel),
1127 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001128 // call this after broadcasting so we do not increment
1129 // if we throw an exeption.
1130 incrementPendingBroadcastsLocked();
1131 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132 } catch (PendingIntent.CanceledException e) {
1133 return false;
1134 }
1135 }
1136 return true;
1137 }
1138
1139 public boolean callLocationChangedLocked(Location location) {
1140 if (mListener != null) {
1141 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001142 synchronized (this) {
1143 // synchronize to ensure incrementPendingBroadcastsLocked()
1144 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001145 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -07001146 // call this after broadcasting so we do not increment
1147 // if we throw an exeption.
1148 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001149 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 } catch (RemoteException e) {
1151 return false;
1152 }
1153 } else {
1154 Intent locationChanged = new Intent();
gomo48f1a642017-11-10 20:35:46 -08001155 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED,
1156 new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001158 synchronized (this) {
1159 // synchronize to ensure incrementPendingBroadcastsLocked()
1160 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001161 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001162 getResolutionPermission(mAllowedResolutionLevel),
1163 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001164 // call this after broadcasting so we do not increment
1165 // if we throw an exeption.
1166 incrementPendingBroadcastsLocked();
1167 }
1168 } catch (PendingIntent.CanceledException e) {
1169 return false;
1170 }
1171 }
1172 return true;
1173 }
1174
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001175 private boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -07001176 // First update AppOp monitoring.
1177 // An app may get/lose location access as providers are enabled/disabled.
1178 updateMonitoring(true);
1179
Mike Lockwood48f17512009-04-23 09:12:08 -07001180 if (mListener != null) {
1181 try {
1182 synchronized (this) {
1183 // synchronize to ensure incrementPendingBroadcastsLocked()
1184 // is called before decrementPendingBroadcasts()
1185 if (enabled) {
1186 mListener.onProviderEnabled(provider);
1187 } else {
1188 mListener.onProviderDisabled(provider);
1189 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001190 // call this after broadcasting so we do not increment
1191 // if we throw an exeption.
1192 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001193 }
1194 } catch (RemoteException e) {
1195 return false;
1196 }
1197 } else {
1198 Intent providerIntent = new Intent();
1199 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
1200 try {
1201 synchronized (this) {
1202 // synchronize to ensure incrementPendingBroadcastsLocked()
1203 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001204 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001205 getResolutionPermission(mAllowedResolutionLevel),
1206 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001207 // call this after broadcasting so we do not increment
1208 // if we throw an exeption.
1209 incrementPendingBroadcastsLocked();
1210 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211 } catch (PendingIntent.CanceledException e) {
1212 return false;
1213 }
1214 }
1215 return true;
1216 }
1217
Nick Pellyf1be6862012-05-15 10:53:42 -07001218 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001220 if (D) Log.d(TAG, "Location listener died");
1221
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001222 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001223 removeUpdatesLocked(this);
1224 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001225 synchronized (this) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001226 clearPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001227 }
1228 }
1229
Nick Pellye0fd6932012-07-11 10:26:13 -07001230 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001231 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1232 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001233 synchronized (this) {
1234 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001235 }
1236 }
1237
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001238 // this must be called while synchronized by caller in a synchronized block
1239 // containing the sending of the broadcaset
1240 private void incrementPendingBroadcastsLocked() {
Yu-Han Yang24189822018-07-11 15:24:11 -07001241 mPendingBroadcasts++;
1242 mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001243 }
1244
1245 private void decrementPendingBroadcastsLocked() {
1246 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001247 if (mWakeLock.isHeld()) {
1248 mWakeLock.release();
1249 }
1250 }
1251 }
1252
1253 public void clearPendingBroadcastsLocked() {
1254 if (mPendingBroadcasts > 0) {
1255 mPendingBroadcasts = 0;
1256 if (mWakeLock.isHeld()) {
1257 mWakeLock.release();
1258 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001259 }
1260 }
1261 }
1262
Nick Pellye0fd6932012-07-11 10:26:13 -07001263 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001264 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001265 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -04001266 //the receiver list if it is not found. If it is not found then the
1267 //LocationListener was removed when it had a pending broadcast and should
1268 //not be added back.
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001269 synchronized (mLock) {
1270 IBinder binder = listener.asBinder();
1271 Receiver receiver = mReceivers.get(binder);
1272 if (receiver != null) {
1273 synchronized (receiver) {
1274 // so wakelock calls will succeed
1275 long identity = Binder.clearCallingIdentity();
1276 receiver.decrementPendingBroadcastsLocked();
1277 Binder.restoreCallingIdentity(identity);
David Christie2ff96af2014-01-30 16:09:37 -08001278 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001279 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001280 }
1281 }
1282
Lifu Tang82f893d2016-01-21 18:15:33 -08001283 /**
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001284 * Returns the year of the GNSS hardware.
Lifu Tang82f893d2016-01-21 18:15:33 -08001285 */
1286 @Override
Lifu Tang9363b942016-02-16 18:07:00 -08001287 public int getGnssYearOfHardware() {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001288 if (mGnssSystemInfoProvider != null) {
Lifu Tang9363b942016-02-16 18:07:00 -08001289 return mGnssSystemInfoProvider.getGnssYearOfHardware();
Lifu Tang82f893d2016-01-21 18:15:33 -08001290 } else {
1291 return 0;
1292 }
1293 }
1294
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001295
1296 /**
1297 * Returns the model name of the GNSS hardware.
1298 */
1299 @Override
Wyatt Riley49097c02018-03-15 09:14:43 -07001300 @Nullable
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001301 public String getGnssHardwareModelName() {
1302 if (mGnssSystemInfoProvider != null) {
1303 return mGnssSystemInfoProvider.getGnssHardwareModelName();
1304 } else {
Wyatt Riley49097c02018-03-15 09:14:43 -07001305 return null;
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001306 }
1307 }
1308
Wyatt Rileycf879db2017-01-12 13:57:38 -08001309 /**
1310 * Runs some checks for GNSS (FINE) level permissions, used by several methods which directly
1311 * (try to) access GNSS information at this layer.
1312 */
1313 private boolean hasGnssPermissions(String packageName) {
1314 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1315 checkResolutionLevelIsSufficientForProviderUse(
1316 allowedResolutionLevel,
1317 LocationManager.GPS_PROVIDER);
1318
1319 int pid = Binder.getCallingPid();
1320 int uid = Binder.getCallingUid();
1321 long identity = Binder.clearCallingIdentity();
1322 boolean hasLocationAccess;
1323 try {
1324 hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1325 } finally {
1326 Binder.restoreCallingIdentity(identity);
1327 }
1328
1329 return hasLocationAccess;
1330 }
1331
1332 /**
1333 * Returns the GNSS batching size, if available.
1334 */
1335 @Override
1336 public int getGnssBatchSize(String packageName) {
1337 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1338 "Location Hardware permission not granted to access hardware batching");
1339
1340 if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
Yu-Han Yang3557cc72018-03-21 12:48:36 -07001341 return mGnssBatchingProvider.getBatchSize();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001342 } else {
1343 return 0;
1344 }
1345 }
1346
1347 /**
1348 * Adds a callback for GNSS Batching events, if permissions allow, which are transported
1349 * to potentially multiple listeners by the BatchedLocationCallbackTransport above this.
1350 */
1351 @Override
1352 public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
1353 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1354 "Location Hardware permission not granted to access hardware batching");
1355
1356 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1357 return false;
1358 }
1359
1360 mGnssBatchingCallback = callback;
1361 mGnssBatchingDeathCallback = new LinkedCallback(callback);
1362 try {
1363 callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
1364 } catch (RemoteException e) {
1365 // if the remote process registering the listener is already dead, just swallow the
1366 // exception and return
1367 Log.e(TAG, "Remote listener already died.", e);
1368 return false;
1369 }
1370
1371 return true;
1372 }
1373
1374 private class LinkedCallback implements IBinder.DeathRecipient {
1375 private final IBatchedLocationCallback mCallback;
1376
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001377 private LinkedCallback(@NonNull IBatchedLocationCallback callback) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001378 mCallback = callback;
1379 }
1380
1381 @NonNull
1382 public IBatchedLocationCallback getUnderlyingListener() {
1383 return mCallback;
1384 }
1385
1386 @Override
1387 public void binderDied() {
1388 Log.d(TAG, "Remote Batching Callback died: " + mCallback);
1389 stopGnssBatch();
1390 removeGnssBatchingCallback();
1391 }
1392 }
1393
1394 /**
1395 * Removes callback for GNSS batching
1396 */
1397 @Override
1398 public void removeGnssBatchingCallback() {
1399 try {
1400 mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
1401 0 /* flags */);
1402 } catch (NoSuchElementException e) {
1403 // if the death callback isn't connected (it should be...), log error, swallow the
1404 // exception and return
1405 Log.e(TAG, "Couldn't unlink death callback.", e);
1406 }
1407 mGnssBatchingCallback = null;
1408 mGnssBatchingDeathCallback = null;
1409 }
1410
1411
1412 /**
1413 * Starts GNSS batching, if available.
1414 */
1415 @Override
1416 public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
1417 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1418 "Location Hardware permission not granted to access hardware batching");
1419
1420 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1421 return false;
1422 }
1423
1424 if (mGnssBatchingInProgress) {
1425 // Current design does not expect multiple starts to be called repeatedly
1426 Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
1427 // Try to clean up anyway, and continue
1428 stopGnssBatch();
1429 }
1430
1431 mGnssBatchingInProgress = true;
1432 return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
1433 }
1434
1435 /**
1436 * Flushes a GNSS batch in progress
1437 */
1438 @Override
1439 public void flushGnssBatch(String packageName) {
1440 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1441 "Location Hardware permission not granted to access hardware batching");
1442
1443 if (!hasGnssPermissions(packageName)) {
1444 Log.e(TAG, "flushGnssBatch called without GNSS permissions");
1445 return;
1446 }
1447
1448 if (!mGnssBatchingInProgress) {
1449 Log.w(TAG, "flushGnssBatch called with no batch in progress");
1450 }
1451
1452 if (mGnssBatchingProvider != null) {
gomo48f1a642017-11-10 20:35:46 -08001453 mGnssBatchingProvider.flush();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001454 }
1455 }
1456
1457 /**
1458 * Stops GNSS batching
1459 */
1460 @Override
1461 public boolean stopGnssBatch() {
1462 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1463 "Location Hardware permission not granted to access hardware batching");
1464
1465 if (mGnssBatchingProvider != null) {
1466 mGnssBatchingInProgress = false;
1467 return mGnssBatchingProvider.stop();
gomo48f1a642017-11-10 20:35:46 -08001468 } else {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001469 return false;
1470 }
1471 }
1472
1473 @Override
1474 public void reportLocationBatch(List<Location> locations) {
1475 checkCallerIsProvider();
1476
1477 // Currently used only for GNSS locations - update permissions check if changed
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001478 if (isAllowedByUserSettingsLockedForUser(LocationManager.GPS_PROVIDER, mCurrentUserId)) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001479 if (mGnssBatchingCallback == null) {
1480 Slog.e(TAG, "reportLocationBatch() called without active Callback");
1481 return;
1482 }
1483 try {
1484 mGnssBatchingCallback.onLocationBatch(locations);
1485 } catch (RemoteException e) {
1486 Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
1487 }
1488 } else {
1489 Slog.w(TAG, "reportLocationBatch() called without user permission, locations blocked");
1490 }
1491 }
1492
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001493 private void addProviderLocked(LocationProvider provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001494 mProviders.add(provider);
1495 mProvidersByName.put(provider.getName(), provider);
1496 }
1497
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001498 private void removeProviderLocked(LocationProvider provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001499 mProviders.remove(provider);
1500 mProvidersByName.remove(provider.getName());
1501 }
1502
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001503 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -08001504 * Returns "true" if access to the specified location provider is allowed by the specified
1505 * user's settings. Access to all location providers is forbidden to non-location-provider
1506 * processes belonging to background users.
1507 *
1508 * @param provider the name of the location provider
Maggie2a9409e2018-03-21 11:47:28 -07001509 * @param userId the user id to query
Victoria Lease09eeaec2013-02-05 11:34:13 -08001510 */
Maggie2a9409e2018-03-21 11:47:28 -07001511 private boolean isAllowedByUserSettingsLockedForUser(String provider, int userId) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001512 if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1513 return isLocationEnabledForUser(userId);
Maggie2a9409e2018-03-21 11:47:28 -07001514 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001515 if (LocationManager.FUSED_PROVIDER.equals(provider)) {
1516 return isLocationEnabledForUser(userId);
Maggie2a9409e2018-03-21 11:47:28 -07001517 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001518 synchronized (mLock) {
1519 if (mMockProviders.containsKey(provider)) {
1520 return isLocationEnabledForUser(userId);
1521 }
1522 }
1523
1524 long identity = Binder.clearCallingIdentity();
1525 try {
1526 // Use system settings
1527 ContentResolver cr = mContext.getContentResolver();
1528 String allowedProviders = Settings.Secure.getStringForUser(
1529 cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId);
1530 return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
1531 } finally {
1532 Binder.restoreCallingIdentity(identity);
1533 }
Maggie2a9409e2018-03-21 11:47:28 -07001534 }
1535
1536
1537 /**
1538 * Returns "true" if access to the specified location provider is allowed by the specified
1539 * user's settings. Access to all location providers is forbidden to non-location-provider
1540 * processes belonging to background users.
1541 *
1542 * @param provider the name of the location provider
1543 * @param uid the requestor's UID
1544 * @param userId the user id to query
1545 */
1546 private boolean isAllowedByUserSettingsLocked(String provider, int uid, int userId) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001547 if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001548 return false;
1549 }
Maggie2a9409e2018-03-21 11:47:28 -07001550 return isAllowedByUserSettingsLockedForUser(provider, userId);
Victoria Lease09eeaec2013-02-05 11:34:13 -08001551 }
1552
1553 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001554 * Returns the permission string associated with the specified resolution level.
1555 *
1556 * @param resolutionLevel the resolution level
1557 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001558 */
Victoria Lease37425c32012-10-16 16:08:48 -07001559 private String getResolutionPermission(int resolutionLevel) {
1560 switch (resolutionLevel) {
1561 case RESOLUTION_LEVEL_FINE:
1562 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1563 case RESOLUTION_LEVEL_COARSE:
1564 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1565 default:
1566 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001567 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001568 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001569
Victoria Leaseda479c52012-10-15 15:24:16 -07001570 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001571 * Returns the resolution level allowed to the given PID/UID pair.
1572 *
1573 * @param pid the PID
1574 * @param uid the UID
1575 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -07001576 */
Victoria Lease37425c32012-10-16 16:08:48 -07001577 private int getAllowedResolutionLevel(int pid, int uid) {
1578 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001579 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001580 return RESOLUTION_LEVEL_FINE;
1581 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001582 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001583 return RESOLUTION_LEVEL_COARSE;
1584 } else {
1585 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001586 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001587 }
1588
1589 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001590 * Returns the resolution level allowed to the caller
1591 *
1592 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -07001593 */
Victoria Lease37425c32012-10-16 16:08:48 -07001594 private int getCallerAllowedResolutionLevel() {
1595 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1596 }
1597
1598 /**
1599 * Throw SecurityException if specified resolution level is insufficient to use geofences.
1600 *
1601 * @param allowedResolutionLevel resolution level allowed to caller
1602 */
1603 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1604 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001605 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1606 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 }
1608
Victoria Lease37425c32012-10-16 16:08:48 -07001609 /**
1610 * Return the minimum resolution level required to use the specified location provider.
1611 *
1612 * @param provider the name of the location provider
1613 * @return minimum resolution level required for provider
1614 */
1615 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001616 if (LocationManager.GPS_PROVIDER.equals(provider) ||
1617 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1618 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001619 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -07001620 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1621 LocationManager.FUSED_PROVIDER.equals(provider)) {
1622 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001623 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001624 } else {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001625 for (LocationProvider lp : mProviders) {
1626 if (!lp.getName().equals(provider)) {
1627 continue;
1628 }
1629
Laurent Tu941221c2012-10-04 14:21:52 -07001630 ProviderProperties properties = lp.getProperties();
1631 if (properties != null) {
1632 if (properties.mRequiresSatellite) {
1633 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001634 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001635 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1636 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001637 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001638 }
1639 }
1640 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001641 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001642
Victoria Lease37425c32012-10-16 16:08:48 -07001643 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001644 }
1645
Victoria Lease37425c32012-10-16 16:08:48 -07001646 /**
1647 * Throw SecurityException if specified resolution level is insufficient to use the named
1648 * location provider.
1649 *
1650 * @param allowedResolutionLevel resolution level allowed to caller
gomo48f1a642017-11-10 20:35:46 -08001651 * @param providerName the name of the location provider
Victoria Lease37425c32012-10-16 16:08:48 -07001652 */
1653 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1654 String providerName) {
1655 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1656 if (allowedResolutionLevel < requiredResolutionLevel) {
1657 switch (requiredResolutionLevel) {
1658 case RESOLUTION_LEVEL_FINE:
1659 throw new SecurityException("\"" + providerName + "\" location provider " +
1660 "requires ACCESS_FINE_LOCATION permission.");
1661 case RESOLUTION_LEVEL_COARSE:
1662 throw new SecurityException("\"" + providerName + "\" location provider " +
1663 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1664 default:
1665 throw new SecurityException("Insufficient permission for \"" + providerName +
1666 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001667 }
1668 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001669 }
1670
David Christie82edc9b2013-07-19 11:31:42 -07001671 /**
1672 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
1673 * for battery).
1674 */
David Christie40e57822013-07-30 11:36:48 -07001675 private void checkDeviceStatsAllowed() {
David Christie82edc9b2013-07-19 11:31:42 -07001676 mContext.enforceCallingOrSelfPermission(
1677 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
1678 }
1679
David Christie40e57822013-07-30 11:36:48 -07001680 private void checkUpdateAppOpsAllowed() {
1681 mContext.enforceCallingOrSelfPermission(
1682 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
1683 }
1684
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001685 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001686 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1687 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001688 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001689 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001690 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001691 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001692 }
1693 return -1;
1694 }
1695
Wei Wangb86334f2018-07-03 16:33:24 -07001696 private static String resolutionLevelToOpStr(int allowedResolutionLevel) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001697 switch (allowedResolutionLevel) {
Wei Wangb86334f2018-07-03 16:33:24 -07001698 case RESOLUTION_LEVEL_COARSE:
1699 return AppOpsManager.OPSTR_COARSE_LOCATION;
1700 case RESOLUTION_LEVEL_FINE:
1701 return AppOpsManager.OPSTR_FINE_LOCATION;
1702 case RESOLUTION_LEVEL_NONE:
1703 // The client is not allowed to get any location, so both FINE and COARSE ops will
1704 // be denied. Pick the most restrictive one to be safe.
1705 return AppOpsManager.OPSTR_FINE_LOCATION;
1706 default:
1707 // Use the most restrictive ops if not sure.
1708 return AppOpsManager.OPSTR_FINE_LOCATION;
1709 }
1710 }
1711
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001712 private boolean reportLocationAccessNoThrow(
David Christieb870dbf2015-06-22 12:42:53 -07001713 int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001714 int op = resolutionLevelToOp(allowedResolutionLevel);
1715 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001716 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1717 return false;
1718 }
1719 }
David Christieb870dbf2015-06-22 12:42:53 -07001720
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001721 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001722 }
1723
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001724 private boolean checkLocationAccess(int pid, int uid, String packageName,
1725 int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001726 int op = resolutionLevelToOp(allowedResolutionLevel);
1727 if (op >= 0) {
Wei Wangdd070f22018-06-21 11:29:40 -07001728 if (mAppOps.noteOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001729 return false;
1730 }
1731 }
David Christieb870dbf2015-06-22 12:42:53 -07001732
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001733 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001734 }
1735
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001736 /**
Maggie91e630c2018-01-24 17:31:46 -08001737 * Returns all providers by name, including passive and the ones that are not permitted to
1738 * be accessed by the calling activity or are currently disabled, but excluding fused.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001739 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001740 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001741 public List<String> getAllProviders() {
Maggie91e630c2018-01-24 17:31:46 -08001742 ArrayList<String> out;
1743 synchronized (mLock) {
1744 out = new ArrayList<>(mProviders.size());
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001745 for (LocationProvider provider : mProviders) {
Maggie91e630c2018-01-24 17:31:46 -08001746 String name = provider.getName();
1747 if (LocationManager.FUSED_PROVIDER.equals(name)) {
1748 continue;
1749 }
1750 out.add(name);
1751 }
1752 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001753 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 return out;
1755 }
1756
Mike Lockwood03ca2162010-04-01 08:10:09 -07001757 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001758 * Return all providers by name, that match criteria and are optionally
1759 * enabled.
1760 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001761 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001762 @Override
1763 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001764 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001765 ArrayList<String> out;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001766 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07001767 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001768 try {
1769 synchronized (mLock) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001770 out = new ArrayList<>(mProviders.size());
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001771 for (LocationProvider provider : mProviders) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001772 String name = provider.getName();
1773 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001774 continue;
1775 }
Victoria Lease37425c32012-10-16 16:08:48 -07001776 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Maggie2a9409e2018-03-21 11:47:28 -07001777 if (enabledOnly
1778 && !isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001779 continue;
1780 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001781 if (criteria != null
1782 && !android.location.LocationProvider.propertiesMeetCriteria(
Victoria Leaseb711d572012-10-02 13:14:11 -07001783 name, provider.getProperties(), criteria)) {
1784 continue;
1785 }
1786 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001787 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001788 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001789 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001790 } finally {
1791 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001792 }
1793
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001794 if (D) Log.d(TAG, "getProviders()=" + out);
1795 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001796 }
1797
1798 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001799 * Return the name of the best provider given a Criteria object.
1800 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001801 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001802 * has been deprecated as well. So this method now uses
1803 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001804 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001805 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001806 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001807 String result;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001808
1809 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001810 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001811 result = pickBest(providers);
1812 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1813 return result;
1814 }
1815 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001816 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001817 result = pickBest(providers);
1818 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1819 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001820 }
1821
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001822 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + null);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001823 return null;
1824 }
1825
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001826 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -07001827 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001828 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -07001829 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1830 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001831 } else {
1832 return providers.get(0);
1833 }
1834 }
1835
Nick Pellye0fd6932012-07-11 10:26:13 -07001836 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001837 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001838 LocationProvider p = mProvidersByName.get(provider);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001839 if (p == null) {
1840 throw new IllegalArgumentException("provider=" + provider);
1841 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001842
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001843 boolean result = android.location.LocationProvider.propertiesMeetCriteria(
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001844 p.getName(), p.getProperties(), criteria);
1845 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1846 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001847 }
1848
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001849 private void updateProvidersSettingsLocked() {
1850 for (LocationProvider p : mProviders) {
1851 p.setSettingsEnabled(isAllowedByUserSettingsLockedForUser(p.getName(), mCurrentUserId));
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001852 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001853
1854 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1855 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001856 }
1857
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001858 private void updateProviderListenersLocked(String provider) {
1859 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001860 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001861
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001862 boolean enabled = p.isEnabled();
1863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001864 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001865
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001866 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1867 if (records != null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001868 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001869 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001870 // Sends a notification message to the receiver
1871 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1872 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001873 deadReceivers = new ArrayList<>();
Victoria Leaseb711d572012-10-02 13:14:11 -07001874 }
1875 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001877 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001878 }
1879 }
1880
1881 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001882 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001883 removeUpdatesLocked(deadReceivers.get(i));
1884 }
1885 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001886
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001887 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001888 }
1889
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001890 private void applyRequirementsLocked(String provider) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001891 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001892 if (p == null) return;
1893
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001894 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001895 WorkSource worksource = new WorkSource();
1896 ProviderRequest providerRequest = new ProviderRequest();
1897
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001898 ContentResolver resolver = mContext.getContentResolver();
1899 long backgroundThrottleInterval = Settings.Global.getLong(
1900 resolver,
1901 Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
1902 DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
1903
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001904 if (p.isEnabled() && records != null && !records.isEmpty()) {
1905 // initialize the low power mode to true and set to false if any of the records requires
1906 providerRequest.lowPowerMode = true;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001907 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001908 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
David Christieb870dbf2015-06-22 12:42:53 -07001909 if (checkLocationAccess(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001910 record.mReceiver.mIdentity.mPid,
1911 record.mReceiver.mIdentity.mUid,
1912 record.mReceiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001913 record.mReceiver.mAllowedResolutionLevel)) {
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001914 LocationRequest locationRequest = record.mRealRequest;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001915 long interval = locationRequest.getInterval();
1916
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001917 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001918 if (!record.mIsForegroundUid) {
1919 interval = Math.max(interval, backgroundThrottleInterval);
1920 }
1921 if (interval != locationRequest.getInterval()) {
1922 locationRequest = new LocationRequest(locationRequest);
1923 locationRequest.setInterval(interval);
1924 }
1925 }
1926
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001927 record.mRequest = locationRequest;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001928 providerRequest.locationRequests.add(locationRequest);
gomo48f1a642017-11-10 20:35:46 -08001929 if (!locationRequest.isLowPowerMode()) {
1930 providerRequest.lowPowerMode = false;
1931 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001932 if (interval < providerRequest.interval) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001933 providerRequest.reportLocation = true;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001934 providerRequest.interval = interval;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001935 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001936 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001937 }
1938 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001939
1940 if (providerRequest.reportLocation) {
1941 // calculate who to blame for power
1942 // This is somewhat arbitrary. We pick a threshold interval
1943 // that is slightly higher that the minimum interval, and
1944 // spread the blame across all applications with a request
1945 // under that threshold.
1946 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1947 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001948 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001949 LocationRequest locationRequest = record.mRequest;
Svet Ganove998c732016-06-10 00:12:38 -07001950
1951 // Don't assign battery blame for update records whose
1952 // client has no permission to receive location data.
1953 if (!providerRequest.locationRequests.contains(locationRequest)) {
1954 continue;
1955 }
1956
Victoria Leaseb711d572012-10-02 13:14:11 -07001957 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07001958 if (record.mReceiver.mWorkSource != null
Narayan Kamath32684dd2018-01-08 17:32:51 +00001959 && isValidWorkSource(record.mReceiver.mWorkSource)) {
David Christie82edc9b2013-07-19 11:31:42 -07001960 worksource.add(record.mReceiver.mWorkSource);
1961 } else {
Narayan Kamath32684dd2018-01-08 17:32:51 +00001962 // Assign blame to caller if there's no WorkSource associated with
1963 // the request or if it's invalid.
David Christie82edc9b2013-07-19 11:31:42 -07001964 worksource.add(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001965 record.mReceiver.mIdentity.mUid,
1966 record.mReceiver.mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07001967 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001968 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001969 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001970 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001971 }
1972 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001973
1974 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1975 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001976 }
1977
Narayan Kamath32684dd2018-01-08 17:32:51 +00001978 /**
1979 * Whether a given {@code WorkSource} associated with a Location request is valid.
1980 */
1981 private static boolean isValidWorkSource(WorkSource workSource) {
1982 if (workSource.size() > 0) {
1983 // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
1984 // by tags.
1985 return workSource.getName(0) != null;
1986 } else {
1987 // For now, make sure callers have supplied an attribution tag for use with
1988 // AppOpsManager. This might be relaxed in the future.
1989 final ArrayList<WorkChain> workChains = workSource.getWorkChains();
1990 return workChains != null && !workChains.isEmpty() &&
1991 workChains.get(0).getAttributionTag() != null;
1992 }
1993 }
1994
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001995 @Override
1996 public String[] getBackgroundThrottlingWhitelist() {
1997 synchronized (mLock) {
1998 return mBackgroundThrottlePackageWhitelist.toArray(
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001999 new String[0]);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002000 }
2001 }
2002
2003 private void updateBackgroundThrottlingWhitelistLocked() {
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08002004 String setting = Settings.Global.getString(
gomo48f1a642017-11-10 20:35:46 -08002005 mContext.getContentResolver(),
2006 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08002007 if (setting == null) {
2008 setting = "";
2009 }
2010
2011 mBackgroundThrottlePackageWhitelist.clear();
2012 mBackgroundThrottlePackageWhitelist.addAll(
gomo48f1a642017-11-10 20:35:46 -08002013 SystemConfig.getInstance().getAllowUnthrottledLocation());
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08002014 mBackgroundThrottlePackageWhitelist.addAll(
gomo48f1a642017-11-10 20:35:46 -08002015 Arrays.asList(setting.split(",")));
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08002016 }
2017
Wei Wangdd070f22018-06-21 11:29:40 -07002018 private void updateLastLocationMaxAgeLocked() {
2019 mLastLocationMaxAgeMs =
2020 Settings.Global.getLong(
2021 mContext.getContentResolver(),
2022 Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
2023 DEFAULT_LAST_LOCATION_MAX_AGE_MS);
2024 }
2025
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002026 private boolean isThrottlingExemptLocked(Identity identity) {
2027 if (identity.mUid == Process.SYSTEM_UID) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002028 return true;
2029 }
2030
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002031 if (mBackgroundThrottlePackageWhitelist.contains(identity.mPackageName)) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002032 return true;
2033 }
2034
2035 for (LocationProviderProxy provider : mProxyProviders) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002036 if (identity.mPackageName.equals(provider.getConnectedPackageName())) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002037 return true;
2038 }
2039 }
2040
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002041 return false;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002042 }
2043
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002044 private class UpdateRecord {
2045 final String mProvider;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002046 private final LocationRequest mRealRequest; // original request from client
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002047 LocationRequest mRequest; // possibly throttled version of the request
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002048 private final Receiver mReceiver;
2049 private boolean mIsForegroundUid;
2050 private Location mLastFixBroadcast;
2051 private long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002052
2053 /**
2054 * Note: must be constructed with lock held.
2055 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002056 private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002057 mProvider = provider;
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002058 mRealRequest = request;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002059 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002060 mReceiver = receiver;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002061 mIsForegroundUid = isImportanceForeground(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002062 mActivityManager.getPackageImportance(mReceiver.mIdentity.mPackageName));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002063
2064 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2065 if (records == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002066 records = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002067 mRecordsByProvider.put(provider, records);
2068 }
2069 if (!records.contains(this)) {
2070 records.add(this);
2071 }
David Christie2ff96af2014-01-30 16:09:37 -08002072
2073 // Update statistics for historical location requests by package/provider
2074 mRequestStatistics.startRequesting(
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002075 mReceiver.mIdentity.mPackageName, provider, request.getInterval(),
2076 mIsForegroundUid);
2077 }
2078
2079 /**
2080 * Method to be called when record changes foreground/background
2081 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002082 private void updateForeground(boolean isForeground) {
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002083 mIsForegroundUid = isForeground;
2084 mRequestStatistics.updateForeground(
2085 mReceiver.mIdentity.mPackageName, mProvider, isForeground);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002086 }
2087
2088 /**
David Christie2ff96af2014-01-30 16:09:37 -08002089 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002090 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002091 private void disposeLocked(boolean removeReceiver) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002092 mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
David Christie2ff96af2014-01-30 16:09:37 -08002093
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002094 // remove from mRecordsByProvider
2095 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
2096 if (globalRecords != null) {
2097 globalRecords.remove(this);
2098 }
2099
2100 if (!removeReceiver) return; // the caller will handle the rest
2101
2102 // remove from Receiver#mUpdateRecords
2103 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002104 receiverRecords.remove(this.mProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002105
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002106 // and also remove the Receiver if it has no more update records
2107 if (receiverRecords.size() == 0) {
2108 removeUpdatesLocked(mReceiver);
Mike Lockwood3a76fd62009-09-01 07:26:56 -04002109 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002110 }
2111
2112 @Override
2113 public String toString() {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002114 return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
gomo48f1a642017-11-10 20:35:46 -08002115 + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground"
2116 : " background")
Wyatt Riley19adc022018-05-22 13:30:51 -07002117 + ")" + " " + mRealRequest + " "
2118 + mReceiver.mWorkSource + "]";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002119 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002120 }
2121
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002122 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07002123 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002124 IBinder binder = listener.asBinder();
2125 Receiver receiver = mReceivers.get(binder);
2126 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002127 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
2128 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002129 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002130 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002131 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002132 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002133 return null;
2134 }
Wen Jingcb3ab222014-03-27 13:42:59 +08002135 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002136 }
2137 return receiver;
2138 }
2139
David Christie82edc9b2013-07-19 11:31:42 -07002140 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07002141 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002142 Receiver receiver = mReceivers.get(intent);
2143 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002144 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
2145 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002146 mReceivers.put(intent, receiver);
2147 }
2148 return receiver;
2149 }
2150
Victoria Lease37425c32012-10-16 16:08:48 -07002151 /**
2152 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
2153 * and consistency requirements.
2154 *
2155 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07002156 * @return a version of request that meets the given resolution and consistency requirements
2157 * @hide
2158 */
gomo48f1a642017-11-10 20:35:46 -08002159 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel,
2160 boolean callerHasLocationHardwarePermission) {
Victoria Lease37425c32012-10-16 16:08:48 -07002161 LocationRequest sanitizedRequest = new LocationRequest(request);
gomo48f1a642017-11-10 20:35:46 -08002162 if (!callerHasLocationHardwarePermission) {
2163 // allow setting low power mode only for callers with location hardware permission
2164 sanitizedRequest.setLowPowerMode(false);
2165 }
Victoria Lease37425c32012-10-16 16:08:48 -07002166 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
2167 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002168 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07002169 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07002170 break;
2171 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07002172 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07002173 break;
2174 }
2175 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07002176 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2177 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002178 }
Victoria Lease37425c32012-10-16 16:08:48 -07002179 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2180 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002181 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002182 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002183 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07002184 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002185 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002186 }
Victoria Lease37425c32012-10-16 16:08:48 -07002187 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002188 }
2189
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002190 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07002191 if (packageName == null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002192 throw new SecurityException("invalid package name: " + null);
Nick Pellye0fd6932012-07-11 10:26:13 -07002193 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002194 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07002195 String[] packages = mPackageManager.getPackagesForUid(uid);
2196 if (packages == null) {
2197 throw new SecurityException("invalid UID " + uid);
2198 }
2199 for (String pkg : packages) {
2200 if (packageName.equals(pkg)) return;
2201 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002202 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002203 }
2204
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002205 private void checkPendingIntent(PendingIntent intent) {
2206 if (intent == null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002207 throw new IllegalArgumentException("invalid pending intent: " + null);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07002208 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002209 }
2210
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002211 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
David Christie40e57822013-07-30 11:36:48 -07002212 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002213 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002214 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002215 } else if (intent != null && listener != null) {
2216 throw new IllegalArgumentException("cannot register both listener and intent");
2217 } else if (intent != null) {
2218 checkPendingIntent(intent);
David Christie40e57822013-07-30 11:36:48 -07002219 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002220 } else {
David Christie40e57822013-07-30 11:36:48 -07002221 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002222 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07002223 }
2224
Nick Pellye0fd6932012-07-11 10:26:13 -07002225 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002226 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
2227 PendingIntent intent, String packageName) {
2228 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2229 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002230 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2231 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2232 request.getProvider());
David Christie82edc9b2013-07-19 11:31:42 -07002233 WorkSource workSource = request.getWorkSource();
Narayan Kamath32684dd2018-01-08 17:32:51 +00002234 if (workSource != null && !workSource.isEmpty()) {
David Christie40e57822013-07-30 11:36:48 -07002235 checkDeviceStatsAllowed();
2236 }
2237 boolean hideFromAppOps = request.getHideFromAppOps();
2238 if (hideFromAppOps) {
2239 checkUpdateAppOpsAllowed();
David Christie82edc9b2013-07-19 11:31:42 -07002240 }
gomo48f1a642017-11-10 20:35:46 -08002241 boolean callerHasLocationHardwarePermission =
2242 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
Maggieaa080f92018-01-04 15:35:11 -08002243 == PERMISSION_GRANTED;
gomo48f1a642017-11-10 20:35:46 -08002244 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
2245 callerHasLocationHardwarePermission);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002246
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002247 final int pid = Binder.getCallingPid();
2248 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002249 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002250 long identity = Binder.clearCallingIdentity();
2251 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002252 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
2253 // a location.
David Christieb870dbf2015-06-22 12:42:53 -07002254 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002255
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002256 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002257 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
David Christie40e57822013-07-30 11:36:48 -07002258 packageName, workSource, hideFromAppOps);
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002259 requestLocationUpdatesLocked(sanitizedRequest, recevier, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04002260 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002261 } finally {
2262 Binder.restoreCallingIdentity(identity);
2263 }
2264 }
2265
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002266 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002267 int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002268 // Figure out the provider. Either its explicitly request (legacy use cases), or
2269 // use the fused provider
2270 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2271 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07002272 if (name == null) {
2273 throw new IllegalArgumentException("provider name must not be null");
2274 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07002275
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002276 LocationProvider provider = mProvidersByName.get(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002277 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07002278 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002279 }
2280
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002281 UpdateRecord record = new UpdateRecord(name, request, receiver);
gomo48f1a642017-11-10 20:35:46 -08002282 if (D) {
2283 Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
2284 + " " + name + " " + request + " from " + packageName + "(" + uid + " "
2285 + (record.mIsForegroundUid ? "foreground" : "background")
2286 + (isThrottlingExemptLocked(receiver.mIdentity)
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002287 ? " [whitelisted]" : "") + ")");
gomo48f1a642017-11-10 20:35:46 -08002288 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002289
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002290 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
2291 if (oldRecord != null) {
2292 oldRecord.disposeLocked(false);
2293 }
2294
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002295 if (provider.isEnabled()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002296 applyRequirementsLocked(name);
2297 } else {
2298 // Notify the listener that updates are currently disabled
2299 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002300 }
David Christie0b837452013-07-29 16:02:13 -07002301 // Update the monitoring here just in case multiple location requests were added to the
2302 // same receiver (this request may be high power and the initial might not have been).
2303 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002304 }
2305
Nick Pellye0fd6932012-07-11 10:26:13 -07002306 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002307 public void removeUpdates(ILocationListener listener, PendingIntent intent,
2308 String packageName) {
2309 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002310
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002311 final int pid = Binder.getCallingPid();
2312 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002313
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002314 synchronized (mLock) {
David Christie40e57822013-07-30 11:36:48 -07002315 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002316 packageName, null, false);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002317
2318 // providers may use public location API's, need to clear identity
2319 long identity = Binder.clearCallingIdentity();
2320 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002321 removeUpdatesLocked(receiver);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002322 } finally {
2323 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002324 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002325 }
2326 }
2327
2328 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08002329 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002330
2331 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
2332 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
2333 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07002334 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002335 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002336 }
2337
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07002338 receiver.updateMonitoring(false);
2339
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002340 // Record which providers were associated with this listener
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002341 HashSet<String> providers = new HashSet<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002342 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
2343 if (oldRecords != null) {
2344 // Call dispose() on the obsolete update records.
2345 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08002346 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002347 record.disposeLocked(false);
2348 }
2349 // Accumulate providers
2350 providers.addAll(oldRecords.keySet());
2351 }
2352
2353 // update provider
2354 for (String provider : providers) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002355 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002356 }
2357 }
2358
Dianne Hackbornc2293022013-02-06 23:14:49 -08002359 private void applyAllProviderRequirementsLocked() {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002360 for (LocationProvider p : mProviders) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08002361 applyRequirementsLocked(p.getName());
2362 }
2363 }
2364
Nick Pellye0fd6932012-07-11 10:26:13 -07002365 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07002366 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002367 if (D) Log.d(TAG, "getLastLocation: " + request);
2368 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002369 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07002370 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002371 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2372 request.getProvider());
2373 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07002374
David Christieb870dbf2015-06-22 12:42:53 -07002375 final int pid = Binder.getCallingPid();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002376 final int uid = Binder.getCallingUid();
2377 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07002378 try {
2379 if (mBlacklist.isBlacklisted(packageName)) {
gomo48f1a642017-11-10 20:35:46 -08002380 if (D) {
2381 Log.d(TAG, "not returning last loc for blacklisted app: " +
2382 packageName);
2383 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002384 return null;
2385 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002386
David Christieb870dbf2015-06-22 12:42:53 -07002387 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08002388 if (D) {
2389 Log.d(TAG, "not returning last loc for no op app: " +
2390 packageName);
2391 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002392 return null;
2393 }
2394
Victoria Leaseb711d572012-10-02 13:14:11 -07002395 synchronized (mLock) {
2396 // Figure out the provider. Either its explicitly request (deprecated API's),
2397 // or use the fused provider
2398 String name = request.getProvider();
2399 if (name == null) name = LocationManager.FUSED_PROVIDER;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002400 LocationProvider provider = mProvidersByName.get(name);
Victoria Leaseb711d572012-10-02 13:14:11 -07002401 if (provider == null) return null;
2402
Maggie2a9409e2018-03-21 11:47:28 -07002403 if (!isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07002404
David Christie1b9b7b12013-04-15 15:31:11 -07002405 Location location;
2406 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2407 // Make sure that an app with coarse permissions can't get frequent location
2408 // updates by calling LocationManager.getLastKnownLocation repeatedly.
2409 location = mLastLocationCoarseInterval.get(name);
2410 } else {
2411 location = mLastLocation.get(name);
2412 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002413 if (location == null) {
2414 return null;
2415 }
Wei Wangdd070f22018-06-21 11:29:40 -07002416
2417 // Don't return stale location to apps with foreground-only location permission.
Wei Wangb86334f2018-07-03 16:33:24 -07002418 String op = resolutionLevelToOpStr(allowedResolutionLevel);
Wei Wangdd070f22018-06-21 11:29:40 -07002419 long locationAgeMs = SystemClock.elapsedRealtime() -
2420 location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
2421 if ((locationAgeMs > mLastLocationMaxAgeMs)
2422 && (mAppOps.unsafeCheckOp(op, uid, packageName)
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002423 == AppOpsManager.MODE_FOREGROUND)) {
Wei Wangdd070f22018-06-21 11:29:40 -07002424 return null;
2425 }
2426
Victoria Lease37425c32012-10-16 16:08:48 -07002427 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
gomo48f1a642017-11-10 20:35:46 -08002428 Location noGPSLocation = location.getExtraLocation(
2429 Location.EXTRA_NO_GPS_LOCATION);
Victoria Leaseb711d572012-10-02 13:14:11 -07002430 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08002431 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07002432 }
Victoria Lease37425c32012-10-16 16:08:48 -07002433 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08002434 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07002435 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002436 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002437 return null;
2438 } finally {
2439 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002440 }
2441 }
2442
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002443 /**
2444 * Provides an interface to inject and set the last location if location is not available
2445 * currently.
2446 *
2447 * This helps in cases where the product (Cars for example) has saved the last known location
2448 * before powering off. This interface lets the client inject the saved location while the GPS
2449 * chipset is getting its first fix, there by improving user experience.
2450 *
2451 * @param location - Location object to inject
2452 * @return true if update was successful, false if not
2453 */
2454 @Override
2455 public boolean injectLocation(Location location) {
2456 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
2457 "Location Hardware permission not granted to inject location");
2458 mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
2459 "Access Fine Location permission not granted to inject Location");
2460
2461 if (location == null) {
2462 if (D) {
2463 Log.d(TAG, "injectLocation(): called with null location");
2464 }
2465 return false;
2466 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002467 LocationProvider p = null;
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002468 String provider = location.getProvider();
2469 if (provider != null) {
2470 p = mProvidersByName.get(provider);
2471 }
2472 if (p == null) {
2473 if (D) {
2474 Log.d(TAG, "injectLocation(): unknown provider");
2475 }
2476 return false;
2477 }
2478 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002479 if (!isAllowedByUserSettingsLockedForUser(provider, mCurrentUserId)) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002480 if (D) {
2481 Log.d(TAG, "Location disabled in Settings for current user:" + mCurrentUserId);
2482 }
2483 return false;
2484 } else {
2485 // NOTE: If last location is already available, location is not injected. If
2486 // provider's normal source (like a GPS chipset) have already provided an output,
2487 // there is no need to inject this location.
2488 if (mLastLocation.get(provider) == null) {
2489 updateLastLocationLocked(location, provider);
2490 } else {
2491 if (D) {
2492 Log.d(TAG, "injectLocation(): Location exists. Not updating");
2493 }
2494 return false;
2495 }
2496 }
2497 }
2498 return true;
2499 }
2500
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002501 @Override
2502 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
2503 String packageName) {
2504 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002505 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2506 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002507 checkPendingIntent(intent);
2508 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002509 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2510 request.getProvider());
gomo48f1a642017-11-10 20:35:46 -08002511 // Require that caller can manage given document
2512 boolean callerHasLocationHardwarePermission =
2513 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
Maggieaa080f92018-01-04 15:35:11 -08002514 == PERMISSION_GRANTED;
gomo48f1a642017-11-10 20:35:46 -08002515 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
2516 callerHasLocationHardwarePermission);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002517
Victoria Lease37425c32012-10-16 16:08:48 -07002518 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002519
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002520 // geo-fence manager uses the public location API, need to clear identity
2521 int uid = Binder.getCallingUid();
Xiaohui Chena4490622015-09-22 15:29:31 -07002522 // TODO: http://b/23822629
2523 if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
Victoria Lease56e675b2012-11-05 19:25:06 -08002524 // temporary measure until geofences work for secondary users
2525 Log.w(TAG, "proximity alerts are currently available only to the primary user");
2526 return;
2527 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002528 long identity = Binder.clearCallingIdentity();
2529 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002530 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
2531 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002532 } finally {
2533 Binder.restoreCallingIdentity(identity);
2534 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002535 }
2536
2537 @Override
2538 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002539 checkPendingIntent(intent);
2540 checkPackageName(packageName);
2541
2542 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
2543
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002544 // geo-fence manager uses the public location API, need to clear identity
2545 long identity = Binder.clearCallingIdentity();
2546 try {
2547 mGeofenceManager.removeFence(geofence, intent);
2548 } finally {
2549 Binder.restoreCallingIdentity(identity);
2550 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002551 }
2552
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002553 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002554 public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002555 if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09002556 return false;
2557 }
2558
Anil Admal75b9fd62018-11-28 11:22:50 -08002559 // TODO(b/120449926): The GNSS status listeners should be handled similar to the GNSS
2560 // measurements listeners.
2561 return mGnssStatusProvider.addListener(callback, Binder.getCallingUid(), packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002562 }
2563
Nick Pellye0fd6932012-07-11 10:26:13 -07002564 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002565 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002566 mGnssStatusProvider.removeListener(callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002567 }
2568
Nick Pellye0fd6932012-07-11 10:26:13 -07002569 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002570 public boolean addGnssMeasurementsListener(
gomo48f1a642017-11-10 20:35:46 -08002571 IGnssMeasurementsListener listener, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002572 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07002573 return false;
2574 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002575
2576 synchronized (mLock) {
2577 Identity callerIdentity
2578 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Anil Admal75b9fd62018-11-28 11:22:50 -08002579 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002580 mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002581 long identity = Binder.clearCallingIdentity();
2582 try {
2583 if (isThrottlingExemptLocked(callerIdentity)
2584 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002585 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002586 return mGnssMeasurementsProvider.addListener(listener,
2587 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002588 }
2589 } finally {
2590 Binder.restoreCallingIdentity(identity);
2591 }
2592
2593 return true;
2594 }
destradaaea8a8a62014-06-23 18:19:03 -07002595 }
2596
2597 @Override
gomo226b7b72018-12-12 16:49:39 -08002598 public void injectGnssMeasurementCorrections(
2599 GnssMeasurementCorrections measurementCorrections, String packageName) {
2600 mContext.enforceCallingPermission(
2601 android.Manifest.permission.LOCATION_HARDWARE,
2602 "Location Hardware permission not granted to inject GNSS measurement corrections.");
2603 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2604 mGnssMeasurementsProvider.injectGnssMeasurementCorrections(measurementCorrections);
2605 } else {
2606 Slog.e(TAG, "Can not inject GNSS corrections due to no permission.");
2607 }
2608 }
2609
2610 @Override
2611 public int getGnssCapabilities(String packageName) {
2612 mContext.enforceCallingPermission(
2613 android.Manifest.permission.LOCATION_HARDWARE,
2614 "Location Hardware permission not granted to obrain GNSS chipset capabilities.");
2615 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2616 return -1;
2617 }
2618 return mGnssMeasurementsProvider.getGnssCapabilities();
2619 }
2620
2621 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002622 public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002623 if (mGnssMeasurementsProvider == null) {
2624 return;
2625 }
2626
2627 synchronized (mLock) {
2628 mGnssMeasurementsListeners.remove(listener.asBinder());
2629 mGnssMeasurementsProvider.removeListener(listener);
Wei Liu5241a4c2015-05-11 14:00:36 -07002630 }
destradaaea8a8a62014-06-23 18:19:03 -07002631 }
2632
2633 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002634 public boolean addGnssNavigationMessageListener(
2635 IGnssNavigationMessageListener listener,
destradaa4b3e3932014-07-21 18:01:47 -07002636 String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002637 if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07002638 return false;
2639 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002640
2641 synchronized (mLock) {
2642 Identity callerIdentity
gomo48f1a642017-11-10 20:35:46 -08002643 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Anil Admal75b9fd62018-11-28 11:22:50 -08002644 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002645 mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002646 long identity = Binder.clearCallingIdentity();
2647 try {
2648 if (isThrottlingExemptLocked(callerIdentity)
2649 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002650 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002651 return mGnssNavigationMessageProvider.addListener(listener,
2652 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002653 }
2654 } finally {
2655 Binder.restoreCallingIdentity(identity);
2656 }
2657
2658 return true;
2659 }
destradaa4b3e3932014-07-21 18:01:47 -07002660 }
2661
2662 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002663 public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
2664 if (mGnssNavigationMessageProvider != null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002665 synchronized (mLock) {
Wyatt Riley11cc7492018-01-17 08:48:27 -08002666 mGnssNavigationMessageListeners.remove(listener.asBinder());
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002667 mGnssNavigationMessageProvider.removeListener(listener);
2668 }
Wei Liu5241a4c2015-05-11 14:00:36 -07002669 }
destradaa4b3e3932014-07-21 18:01:47 -07002670 }
2671
2672 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002673 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002674 if (provider == null) {
2675 // throw NullPointerException to remain compatible with previous implementation
2676 throw new NullPointerException();
2677 }
Victoria Lease37425c32012-10-16 16:08:48 -07002678 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2679 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002680
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002681 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04002682 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
Maggieaa080f92018-01-04 15:35:11 -08002683 != PERMISSION_GRANTED)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002684 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2685 }
2686
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002687 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002688 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002689 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07002690
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002691 p.sendExtraCommand(command, extras);
2692 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002693 }
2694 }
2695
Nick Pellye0fd6932012-07-11 10:26:13 -07002696 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002697 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07002698 if (Binder.getCallingUid() != Process.myUid()) {
2699 throw new SecurityException(
2700 "calling sendNiResponse from outside of the system is not allowed");
2701 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04002702 try {
2703 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002704 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002705 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04002706 return false;
2707 }
2708 }
2709
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002710 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002711 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11002712 * @throws SecurityException if the provider is not allowed to be
gomo48f1a642017-11-10 20:35:46 -08002713 * accessed by the caller
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002714 */
Nick Pellye0fd6932012-07-11 10:26:13 -07002715 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002716 public ProviderProperties getProviderProperties(String provider) {
Victoria Lease37425c32012-10-16 16:08:48 -07002717 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2718 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002719
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002720 LocationProvider p;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002721 synchronized (mLock) {
2722 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002723 }
2724
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002725 if (p == null) return null;
2726 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002727 }
2728
Jason Monkb71218a2015-06-17 14:44:39 -04002729 /**
2730 * @return null if the provider does not exist
2731 * @throws SecurityException if the provider is not allowed to be
gomo48f1a642017-11-10 20:35:46 -08002732 * accessed by the caller
Jason Monkb71218a2015-06-17 14:44:39 -04002733 */
2734 @Override
2735 public String getNetworkProviderPackage() {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002736 LocationProvider p;
Jason Monkb71218a2015-06-17 14:44:39 -04002737 synchronized (mLock) {
Jason Monkb71218a2015-06-17 14:44:39 -04002738 p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
2739 }
2740
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002741 if (p == null) {
2742 return null;
2743 }
2744 if (p.mProvider instanceof LocationProviderProxy) {
2745 return ((LocationProviderProxy) p.mProvider).getConnectedPackageName();
Jason Monkb71218a2015-06-17 14:44:39 -04002746 }
2747 return null;
2748 }
2749
Wei Wang980b7c22018-12-06 17:53:00 -08002750 @Override
2751 public void setLocationControllerExtraPackage(String packageName) {
2752 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2753 Manifest.permission.LOCATION_HARDWARE + " permission required");
2754 synchronized (mLock) {
2755 mLocationControllerExtraPackage = packageName;
2756 }
2757 }
2758
2759 @Override
2760 public String getLocationControllerExtraPackage() {
2761 synchronized (mLock) {
2762 return mLocationControllerExtraPackage;
2763 }
2764 }
2765
2766 @Override
2767 public void setLocationControllerExtraPackageEnabled(boolean enabled) {
2768 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2769 Manifest.permission.LOCATION_HARDWARE + " permission required");
2770 synchronized (mLock) {
2771 mLocationControllerExtraPackageEnabled = enabled;
2772 }
2773 }
2774
2775 @Override
2776 public boolean isLocationControllerExtraPackageEnabled() {
2777 synchronized (mLock) {
2778 return mLocationControllerExtraPackageEnabled
2779 && (mLocationControllerExtraPackage != null);
2780 }
2781 }
2782
Maggieaa080f92018-01-04 15:35:11 -08002783 /**
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002784 * Returns the current location enabled/disabled status for a user
Maggie2a9409e2018-03-21 11:47:28 -07002785 *
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002786 * @param userId the id of the user
2787 * @return true if location is enabled
Maggie2a9409e2018-03-21 11:47:28 -07002788 */
2789 @Override
2790 public boolean isLocationEnabledForUser(int userId) {
2791 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2792 checkInteractAcrossUsersPermission(userId);
2793
2794 long identity = Binder.clearCallingIdentity();
2795 try {
2796 synchronized (mLock) {
2797 final String allowedProviders = Settings.Secure.getStringForUser(
2798 mContext.getContentResolver(),
2799 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
2800 userId);
2801 if (allowedProviders == null) {
2802 return false;
2803 }
2804 final List<String> providerList = Arrays.asList(allowedProviders.split(","));
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002805 for (String provider : mRealProviders.keySet()) {
Maggie2a9409e2018-03-21 11:47:28 -07002806 if (provider.equals(LocationManager.PASSIVE_PROVIDER)
2807 || provider.equals(LocationManager.FUSED_PROVIDER)) {
2808 continue;
2809 }
2810 if (providerList.contains(provider)) {
2811 return true;
2812 }
2813 }
2814 return false;
2815 }
2816 } finally {
2817 Binder.restoreCallingIdentity(identity);
2818 }
2819 }
2820
2821 /**
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002822 * Enable or disable location for a user
Maggie2a9409e2018-03-21 11:47:28 -07002823 *
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002824 * @param enabled true to enable location, false to disable location
2825 * @param userId the id of the user
Maggie2a9409e2018-03-21 11:47:28 -07002826 */
2827 @Override
2828 public void setLocationEnabledForUser(boolean enabled, int userId) {
Chad Brubaker90f391f2018-10-19 10:26:19 -07002829 mContext.enforceCallingOrSelfPermission(
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002830 android.Manifest.permission.WRITE_SECURE_SETTINGS,
2831 "Requires WRITE_SECURE_SETTINGS permission");
Maggie2a9409e2018-03-21 11:47:28 -07002832
2833 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2834 checkInteractAcrossUsersPermission(userId);
2835
2836 long identity = Binder.clearCallingIdentity();
2837 try {
2838 synchronized (mLock) {
2839 final Set<String> allRealProviders = mRealProviders.keySet();
2840 // Update all providers on device plus gps and network provider when disabling
2841 // location
2842 Set<String> allProvidersSet = new ArraySet<>(allRealProviders.size() + 2);
2843 allProvidersSet.addAll(allRealProviders);
2844 // When disabling location, disable gps and network provider that could have been
2845 // enabled by location mode api.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002846 if (!enabled) {
Maggie2a9409e2018-03-21 11:47:28 -07002847 allProvidersSet.add(LocationManager.GPS_PROVIDER);
2848 allProvidersSet.add(LocationManager.NETWORK_PROVIDER);
2849 }
2850 if (allProvidersSet.isEmpty()) {
2851 return;
2852 }
2853 // to ensure thread safety, we write the provider name with a '+' or '-'
2854 // and let the SettingsProvider handle it rather than reading and modifying
2855 // the list of enabled providers.
2856 final String prefix = enabled ? "+" : "-";
2857 StringBuilder locationProvidersAllowed = new StringBuilder();
2858 for (String provider : allProvidersSet) {
2859 if (provider.equals(LocationManager.PASSIVE_PROVIDER)
2860 || provider.equals(LocationManager.FUSED_PROVIDER)) {
2861 continue;
2862 }
2863 locationProvidersAllowed.append(prefix);
2864 locationProvidersAllowed.append(provider);
2865 locationProvidersAllowed.append(",");
2866 }
2867 // Remove the trailing comma
2868 locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
2869 Settings.Secure.putStringForUser(
2870 mContext.getContentResolver(),
2871 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
2872 locationProvidersAllowed.toString(),
2873 userId);
2874 }
2875 } finally {
2876 Binder.restoreCallingIdentity(identity);
2877 }
2878 }
2879
2880 /**
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002881 * Returns the current enabled/disabled status of a location provider and user
Maggie2a9409e2018-03-21 11:47:28 -07002882 *
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002883 * @param providerName name of the provider
2884 * @param userId the id of the user
2885 * @return true if the provider exists and is enabled
Maggie2a9409e2018-03-21 11:47:28 -07002886 */
2887 @Override
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002888 public boolean isProviderEnabledForUser(String providerName, int userId) {
Maggie2a9409e2018-03-21 11:47:28 -07002889 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2890 checkInteractAcrossUsersPermission(userId);
2891
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002892 if (!isLocationEnabledForUser(userId)) {
2893 return false;
2894 }
2895
Maggie2a9409e2018-03-21 11:47:28 -07002896 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2897 // so we discourage its use
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002898 if (LocationManager.FUSED_PROVIDER.equals(providerName)) return false;
Maggie2a9409e2018-03-21 11:47:28 -07002899
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002900 long identity = Binder.clearCallingIdentity();
2901 try {
2902 LocationProvider provider;
2903 synchronized (mLock) {
2904 provider = mProvidersByName.get(providerName);
2905 }
2906 return provider != null && provider.isEnabled();
2907 } finally {
2908 Binder.restoreCallingIdentity(identity);
Maggie2a9409e2018-03-21 11:47:28 -07002909 }
2910 }
2911
2912 /**
2913 * Enable or disable a single location provider.
2914 *
2915 * @param provider name of the provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002916 * @param enabled true to enable the provider. False to disable the provider
2917 * @param userId the id of the user to set
Maggie2a9409e2018-03-21 11:47:28 -07002918 * @return true if the value was set, false on errors
2919 */
2920 @Override
2921 public boolean setProviderEnabledForUser(String provider, boolean enabled, int userId) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002922 return false;
Maggieaa080f92018-01-04 15:35:11 -08002923 }
2924
2925 /**
Maggie2a9409e2018-03-21 11:47:28 -07002926 * Method for checking INTERACT_ACROSS_USERS permission if specified user id is not the same as
2927 * current user id
2928 *
2929 * @param userId the user id to get or set value
2930 */
2931 private void checkInteractAcrossUsersPermission(int userId) {
2932 int uid = Binder.getCallingUid();
2933 if (UserHandle.getUserId(uid) != userId) {
2934 if (ActivityManager.checkComponentPermission(
2935 android.Manifest.permission.INTERACT_ACROSS_USERS, uid, -1, true)
2936 != PERMISSION_GRANTED) {
2937 throw new SecurityException("Requires INTERACT_ACROSS_USERS permission");
2938 }
2939 }
2940 }
2941
2942 /**
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002943 * Returns "true" if the UID belongs to a bound location provider.
2944 *
2945 * @param uid the uid
2946 * @return true if uid belongs to a bound location provider
2947 */
2948 private boolean isUidALocationProvider(int uid) {
2949 if (uid == Process.SYSTEM_UID) {
2950 return true;
2951 }
2952 if (mGeocodeProvider != null) {
David Christie1f141c12014-05-14 15:11:15 -07002953 if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002954 }
2955 for (LocationProviderProxy proxy : mProxyProviders) {
David Christie1f141c12014-05-14 15:11:15 -07002956 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002957 }
2958 return false;
2959 }
2960
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002961 private void checkCallerIsProvider() {
2962 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
Maggieaa080f92018-01-04 15:35:11 -08002963 == PERMISSION_GRANTED) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002964 return;
2965 }
2966
2967 // Previously we only used the INSTALL_LOCATION_PROVIDER
2968 // check. But that is system or signature
2969 // protection level which is not flexible enough for
2970 // providers installed oustide the system image. So
2971 // also allow providers with a UID matching the
2972 // currently bound package name
2973
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002974 if (isUidALocationProvider(Binder.getCallingUid())) {
2975 return;
2976 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002977
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002978 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2979 "or UID of a currently bound location provider");
2980 }
2981
David Christie1f141c12014-05-14 15:11:15 -07002982 /**
2983 * Returns true if the given package belongs to the given uid.
2984 */
2985 private boolean doesUidHavePackage(int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002986 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002987 return false;
2988 }
David Christie1f141c12014-05-14 15:11:15 -07002989 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2990 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002991 return false;
2992 }
David Christie1f141c12014-05-14 15:11:15 -07002993 for (String name : packageNames) {
2994 if (packageName.equals(name)) {
2995 return true;
2996 }
2997 }
2998 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002999 }
3000
Nick Pellye0fd6932012-07-11 10:26:13 -07003001 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05003002 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003003 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04003004
Nick Pelly2eeeec22012-07-18 13:13:37 -07003005 if (!location.isComplete()) {
3006 Log.w(TAG, "Dropping incomplete location: " + location);
3007 return;
3008 }
3009
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003010 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
3011 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05003012 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07003013 mLocationHandler.sendMessageAtFrontOfQueue(m);
3014 }
3015
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003016
Laurent Tu75defb62012-11-01 16:21:52 -07003017 private static boolean shouldBroadcastSafe(
3018 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003019 // Always broadcast the first update
3020 if (lastLoc == null) {
3021 return true;
3022 }
3023
Nick Pellyf1be6862012-05-15 10:53:42 -07003024 // Check whether sufficient time has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003025 long minTime = record.mRealRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07003026 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
3027 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003028 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003029 return false;
3030 }
3031
3032 // Check whether sufficient distance has been traveled
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003033 double minDistance = record.mRealRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003034 if (minDistance > 0.0) {
3035 if (loc.distanceTo(lastLoc) <= minDistance) {
3036 return false;
3037 }
3038 }
3039
Laurent Tu75defb62012-11-01 16:21:52 -07003040 // Check whether sufficient number of udpates is left
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003041 if (record.mRealRequest.getNumUpdates() <= 0) {
Laurent Tu75defb62012-11-01 16:21:52 -07003042 return false;
3043 }
3044
3045 // Check whether the expiry date has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003046 return record.mRealRequest.getExpireAt() >= now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003047 }
3048
Mike Lockwooda4903f22010-02-17 06:42:23 -05003049 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07003050 if (D) Log.d(TAG, "incoming location: " + location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003051 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05003052 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
Laurent Tu60ec50a2012-10-04 17:00:10 -07003053 // Skip if the provider is unknown.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003054 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003055 if (p == null) return;
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003056 updateLastLocationLocked(location, provider);
3057 // mLastLocation should have been updated from the updateLastLocationLocked call above.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003058 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07003059 if (lastLocation == null) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003060 Log.e(TAG, "handleLocationChangedLocked() updateLastLocation failed");
3061 return;
Mike Lockwood4e50b782009-04-03 08:24:43 -07003062 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003063
David Christie1b9b7b12013-04-15 15:31:11 -07003064 // Update last known coarse interval location if enough time has passed.
3065 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
3066 if (lastLocationCoarseInterval == null) {
3067 lastLocationCoarseInterval = new Location(location);
3068 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
3069 }
3070 long timeDiffNanos = location.getElapsedRealtimeNanos()
3071 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
3072 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
3073 lastLocationCoarseInterval.set(location);
3074 }
3075 // Don't ever return a coarse location that is more recent than the allowed update
3076 // interval (i.e. don't allow an app to keep registering and unregistering for
3077 // location updates to overcome the minimum interval).
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003078 Location noGPSLocation =
David Christie1b9b7b12013-04-15 15:31:11 -07003079 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3080
Laurent Tu60ec50a2012-10-04 17:00:10 -07003081 // Skip if there are no UpdateRecords for this provider.
3082 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
3083 if (records == null || records.size() == 0) return;
3084
Victoria Lease09016ab2012-09-16 12:33:15 -07003085 // Fetch coarse location
3086 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07003087 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003088 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
3089 }
3090
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003091 // Fetch latest status update time
3092 long newStatusUpdateTime = p.getStatusUpdateTime();
3093
David Christie2ff96af2014-01-30 16:09:37 -08003094 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003095 Bundle extras = new Bundle();
3096 int status = p.getStatus(extras);
3097
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003098 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003099 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07003100
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003101 // Broadcast location to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003102 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003103 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07003104 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07003105
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003106 int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
3107 if (!isCurrentProfile(receiverUserId)
3108 && !isUidALocationProvider(receiver.mIdentity.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07003109 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07003110 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07003111 " (current user: " + mCurrentUserId + ", app: " +
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003112 receiver.mIdentity.mPackageName + ")");
Victoria Leaseb711d572012-10-02 13:14:11 -07003113 }
3114 continue;
3115 }
3116
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003117 if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
gomo48f1a642017-11-10 20:35:46 -08003118 if (D) {
3119 Log.d(TAG, "skipping loc update for blacklisted app: " +
3120 receiver.mIdentity.mPackageName);
3121 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07003122 continue;
3123 }
3124
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003125 if (!reportLocationAccessNoThrow(
3126 receiver.mIdentity.mPid,
3127 receiver.mIdentity.mUid,
3128 receiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003129 receiver.mAllowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08003130 if (D) {
3131 Log.d(TAG, "skipping loc update for no op app: " +
3132 receiver.mIdentity.mPackageName);
3133 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003134 continue;
3135 }
3136
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003137 Location notifyLocation;
Victoria Lease37425c32012-10-16 16:08:48 -07003138 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
3139 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003140 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07003141 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003142 }
Victoria Lease09016ab2012-09-16 12:33:15 -07003143 if (notifyLocation != null) {
3144 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07003145 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003146 if (lastLoc == null) {
3147 lastLoc = new Location(notifyLocation);
3148 r.mLastFixBroadcast = lastLoc;
3149 } else {
3150 lastLoc.set(notifyLocation);
3151 }
3152 if (!receiver.callLocationChangedLocked(notifyLocation)) {
3153 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
3154 receiverDead = true;
3155 }
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003156 r.mRealRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003157 }
3158 }
3159
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003160 // TODO: location provider status callbacks have been disabled and deprecated, and are
3161 // guarded behind this setting now. should be removed completely post-Q
3162 if (Settings.Global.getInt(mContext.getContentResolver(),
3163 LOCATION_DISABLE_STATUS_CALLBACKS, 1) == 0) {
3164 long prevStatusUpdateTime = r.mLastStatusBroadcast;
3165 if ((newStatusUpdateTime > prevStatusUpdateTime)
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003166 && (prevStatusUpdateTime != 0 || status != AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003167
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003168 r.mLastStatusBroadcast = newStatusUpdateTime;
3169 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
3170 receiverDead = true;
3171 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
3172 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07003173 }
3174 }
3175
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003176 // track expired records
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003177 if (r.mRealRequest.getNumUpdates() <= 0 || r.mRealRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003178 if (deadUpdateRecords == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003179 deadUpdateRecords = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003180 }
3181 deadUpdateRecords.add(r);
3182 }
3183 // track dead receivers
3184 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07003185 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003186 deadReceivers = new ArrayList<>();
Mike Lockwood03ca2162010-04-01 08:10:09 -07003187 }
3188 if (!deadReceivers.contains(receiver)) {
3189 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003190 }
3191 }
3192 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003193
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003194 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003195 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003196 for (Receiver receiver : deadReceivers) {
3197 removeUpdatesLocked(receiver);
3198 }
3199 }
3200 if (deadUpdateRecords != null) {
3201 for (UpdateRecord r : deadUpdateRecords) {
3202 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003203 }
Victoria Lease8b38b292012-12-04 15:04:43 -08003204 applyRequirementsLocked(provider);
3205 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003206 }
3207
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003208 /**
3209 * Updates last location with the given location
3210 *
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003211 * @param location new location to update
3212 * @param provider Location provider to update for
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003213 */
3214 private void updateLastLocationLocked(Location location, String provider) {
3215 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3216 Location lastNoGPSLocation;
3217 Location lastLocation = mLastLocation.get(provider);
3218 if (lastLocation == null) {
3219 lastLocation = new Location(provider);
3220 mLastLocation.put(provider, lastLocation);
3221 } else {
3222 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3223 if (noGPSLocation == null && lastNoGPSLocation != null) {
3224 // New location has no no-GPS location: adopt last no-GPS location. This is set
3225 // directly into location because we do not want to notify COARSE clients.
3226 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
3227 }
3228 }
3229 lastLocation.set(location);
3230 }
3231
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003232 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08003233 public LocationWorkerHandler(Looper looper) {
3234 super(looper, null, true);
3235 }
3236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003237 @Override
3238 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003239 switch (msg.what) {
3240 case MSG_LOCATION_CHANGED:
3241 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
3242 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003243 }
3244 }
3245 }
3246
Victoria Lease54ca7ae2013-01-08 09:39:50 -08003247 private boolean isMockProvider(String provider) {
3248 synchronized (mLock) {
3249 return mMockProviders.containsKey(provider);
3250 }
3251 }
3252
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003253 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08003254 // create a working copy of the incoming Location so that the service can modify it without
3255 // disturbing the caller's copy
3256 Location myLocation = new Location(location);
3257 String provider = myLocation.getProvider();
3258
3259 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
3260 // bit if location did not come from a mock provider because passive/fused providers can
3261 // forward locations from mock providers, and should not grant them legitimacy in doing so.
3262 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
3263 myLocation.setIsFromMockProvider(true);
3264 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08003265
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003266 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003267 if (!passive) {
3268 // notify passive provider of the new location
3269 mPassiveProvider.updateLocation(myLocation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003270 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003271 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003272 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003273 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003274
Mike Lockwoode97ae402010-09-29 15:23:46 -04003275 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
3276 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003277 public void onPackageDisappeared(String packageName, int reason) {
3278 // remove all receivers associated with this package name
3279 synchronized (mLock) {
3280 ArrayList<Receiver> deadReceivers = null;
3281
3282 for (Receiver receiver : mReceivers.values()) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003283 if (receiver.mIdentity.mPackageName.equals(packageName)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003284 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003285 deadReceivers = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003286 }
3287 deadReceivers.add(receiver);
3288 }
3289 }
3290
3291 // perform removal outside of mReceivers loop
3292 if (deadReceivers != null) {
3293 for (Receiver receiver : deadReceivers) {
3294 removeUpdatesLocked(receiver);
3295 }
3296 }
3297 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003298 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04003299 };
3300
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003301 // Geocoder
3302
Nick Pellye0fd6932012-07-11 10:26:13 -07003303 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04003304 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07003305 return mGeocodeProvider != null;
3306 }
3307
Nick Pellye0fd6932012-07-11 10:26:13 -07003308 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003309 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003310 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003311 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003312 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
3313 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003314 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003315 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003316 }
3317
Mike Lockwooda55c3212009-04-15 11:10:11 -04003318
Nick Pellye0fd6932012-07-11 10:26:13 -07003319 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003320 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04003321 double lowerLeftLatitude, double lowerLeftLongitude,
3322 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003323 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003324
3325 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003326 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
3327 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
3328 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003329 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003330 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003331 }
3332
3333 // Mock Providers
3334
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003335 private boolean canCallerAccessMockLocation(String opPackageName) {
3336 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
3337 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003338 }
3339
Nick Pellye0fd6932012-07-11 10:26:13 -07003340 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003341 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
3342 if (!canCallerAccessMockLocation(opPackageName)) {
3343 return;
3344 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003345
Mike Lockwooda4903f22010-02-17 06:42:23 -05003346 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
3347 throw new IllegalArgumentException("Cannot mock the passive location provider");
3348 }
3349
Mike Lockwood86328a92009-10-23 08:38:25 -04003350 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003351 synchronized (mLock) {
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003352 // remove the real provider if we are replacing GPS or network provider
3353 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07003354 || LocationManager.NETWORK_PROVIDER.equals(name)
3355 || LocationManager.FUSED_PROVIDER.equals(name)) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003356 LocationProvider p = mProvidersByName.get(name);
Mike Lockwoodd03ff942010-02-09 08:46:14 -05003357 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003358 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003359 }
3360 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003361 addTestProviderLocked(name, properties);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003362 }
Mike Lockwood86328a92009-10-23 08:38:25 -04003363 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003364 }
3365
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003366 private void addTestProviderLocked(String name, ProviderProperties properties) {
3367 if (mProvidersByName.get(name) != null) {
3368 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
3369 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003370
3371 LocationProvider provider = new LocationProvider(name);
3372 MockProvider mockProvider = new MockProvider(provider, properties);
3373
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003374 addProviderLocked(provider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003375 mMockProviders.put(name, mockProvider);
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003376 mLastLocation.put(name, null);
3377 mLastLocationCoarseInterval.put(name, null);
3378 }
3379
Nick Pellye0fd6932012-07-11 10:26:13 -07003380 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003381 public void removeTestProvider(String provider, String opPackageName) {
3382 if (!canCallerAccessMockLocation(opPackageName)) {
3383 return;
3384 }
3385
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003386 synchronized (mLock) {
You Kima6d0b6f2012-10-28 03:58:44 +09003387 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003388 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003389 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3390 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003391
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003392 long identity = Binder.clearCallingIdentity();
3393 try {
3394 removeProviderLocked(mProvidersByName.get(provider));
3395
3396 // reinstate real provider if available
3397 LocationProvider realProvider = mRealProviders.get(provider);
3398 if (realProvider != null) {
3399 addProviderLocked(realProvider);
3400 }
3401 mLastLocation.put(provider, null);
3402 mLastLocationCoarseInterval.put(provider, null);
3403 } finally {
3404 Binder.restoreCallingIdentity(identity);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003405 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003406 }
3407 }
3408
Nick Pellye0fd6932012-07-11 10:26:13 -07003409 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003410 public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
3411 if (!canCallerAccessMockLocation(opPackageName)) {
3412 return;
3413 }
3414
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003415 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003416 MockProvider mockProvider = mMockProviders.get(provider);
3417 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003418 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3419 }
Tom O'Neilla206a0f2016-12-15 10:26:28 -08003420
3421 // Ensure that the location is marked as being mock. There's some logic to do this in
3422 // handleLocationChanged(), but it fails if loc has the wrong provider (bug 33091107).
3423 Location mock = new Location(loc);
3424 mock.setIsFromMockProvider(true);
3425
3426 if (!TextUtils.isEmpty(loc.getProvider()) && !provider.equals(loc.getProvider())) {
3427 // The location has an explicit provider that is different from the mock provider
3428 // name. The caller may be trying to fool us via bug 33091107.
3429 EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
3430 provider + "!=" + loc.getProvider());
3431 }
3432
Mike Lockwood95427cd2009-05-07 13:27:54 -04003433 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
3434 long identity = Binder.clearCallingIdentity();
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003435 try {
3436 mockProvider.setLocation(mock);
3437 } finally {
3438 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003439 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003440 }
3441 }
3442
Nick Pellye0fd6932012-07-11 10:26:13 -07003443 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003444 public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
3445 if (!canCallerAccessMockLocation(opPackageName)) {
3446 return;
3447 }
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003448
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003449 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003450 MockProvider mockProvider = mMockProviders.get(provider);
3451 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003452 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3453 }
Mike Lockwood86328a92009-10-23 08:38:25 -04003454 long identity = Binder.clearCallingIdentity();
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003455 try {
3456 mockProvider.setEnabled(enabled);
3457 } finally {
3458 Binder.restoreCallingIdentity(identity);
3459 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003460 }
3461 }
3462
Nick Pellye0fd6932012-07-11 10:26:13 -07003463 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003464 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
3465 String opPackageName) {
3466 if (!canCallerAccessMockLocation(opPackageName)) {
3467 return;
3468 }
3469
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003470 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003471 MockProvider mockProvider = mMockProviders.get(provider);
3472 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003473 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3474 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003475 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003476 }
3477 }
3478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003479 private void log(String log) {
3480 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003481 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003482 }
3483 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003484
3485 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003486 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06003487 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Nick Pellye0fd6932012-07-11 10:26:13 -07003488
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003489 synchronized (mLock) {
Siddharth Raybb608c82017-03-16 11:33:34 -07003490 if (args.length > 0 && args[0].equals("--gnssmetrics")) {
3491 if (mGnssMetricsProvider != null) {
3492 pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
3493 }
3494 return;
3495 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003496 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003497 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003498 for (Receiver receiver : mReceivers.values()) {
3499 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003500 }
David Christie2ff96af2014-01-30 16:09:37 -08003501 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003502 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
3503 pw.println(" " + entry.getKey() + ":");
3504 for (UpdateRecord record : entry.getValue()) {
3505 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003506 }
3507 }
Wyatt Riley11cc7492018-01-17 08:48:27 -08003508 pw.println(" Active GnssMeasurement Listeners:");
3509 for (Identity identity : mGnssMeasurementsListeners.values()) {
3510 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3511 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3512 }
3513 pw.println(" Active GnssNavigationMessage Listeners:");
3514 for (Identity identity : mGnssNavigationMessageListeners.values()) {
3515 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3516 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3517 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003518 pw.println(" Overlay Provider Packages:");
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003519 for (LocationProvider provider : mProviders) {
3520 if (provider.mProvider instanceof LocationProviderProxy) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003521 pw.println(" " + provider.getName() + ": "
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003522 + ((LocationProviderProxy) provider.mProvider)
3523 .getConnectedPackageName());
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003524 }
3525 }
David Christie2ff96af2014-01-30 16:09:37 -08003526 pw.println(" Historical Records by Provider:");
3527 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
3528 : mRequestStatistics.statistics.entrySet()) {
3529 PackageProviderKey key = entry.getKey();
3530 PackageStatistics stats = entry.getValue();
3531 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
3532 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003533 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003534 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
3535 String provider = entry.getKey();
3536 Location location = entry.getValue();
3537 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003538 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003539
David Christie1b9b7b12013-04-15 15:31:11 -07003540 pw.println(" Last Known Locations Coarse Intervals:");
3541 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
3542 String provider = entry.getKey();
3543 Location location = entry.getValue();
3544 pw.println(" " + provider + ": " + location);
3545 }
3546
Nick Pellye0fd6932012-07-11 10:26:13 -07003547 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003548
Nick Pelly4035f5a2012-08-17 14:43:49 -07003549 pw.append(" ");
3550 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003551 if (mMockProviders.size() > 0) {
3552 pw.println(" Mock Providers:");
3553 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003554 i.getValue().dump(fd, pw, args);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003555 }
3556 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003557
Wei Wang980b7c22018-12-06 17:53:00 -08003558 if (mLocationControllerExtraPackage != null) {
3559 pw.println(" Location controller extra package: " + mLocationControllerExtraPackage
3560 + " enabled: " + mLocationControllerExtraPackageEnabled);
3561 }
3562
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08003563 if (!mBackgroundThrottlePackageWhitelist.isEmpty()) {
3564 pw.println(" Throttling Whitelisted Packages:");
3565 for (String packageName : mBackgroundThrottlePackageWhitelist) {
3566 pw.println(" " + packageName);
3567 }
3568 }
3569
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003570 pw.append(" fudger: ");
gomo48f1a642017-11-10 20:35:46 -08003571 mLocationFudger.dump(fd, pw, args);
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003572
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003573 if (args.length > 0 && "short".equals(args[0])) {
3574 return;
3575 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003576 for (LocationProvider provider : mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003577 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003578 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08003579 if (mGnssBatchingInProgress) {
3580 pw.println(" GNSS batching in progress");
3581 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003582 }
3583 }
3584}