blob: db445c1733fd7d5a6c8e4375d5521fc7f3cae3e0 [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
Wyatt Rileycf879db2017-01-12 13:57:38 -080025import android.annotation.NonNull;
Wyatt Riley49097c02018-03-15 09:14:43 -070026import android.annotation.Nullable;
Maggieaa080f92018-01-04 15:35:11 -080027import android.app.ActivityManager;
28import android.app.AppOpsManager;
29import android.app.PendingIntent;
30import android.content.BroadcastReceiver;
31import android.content.ContentResolver;
32import android.content.Context;
33import android.content.Intent;
34import android.content.IntentFilter;
35import android.content.pm.ApplicationInfo;
36import android.content.pm.PackageInfo;
37import android.content.pm.PackageManager;
38import android.content.pm.PackageManager.NameNotFoundException;
39import android.content.pm.PackageManagerInternal;
40import android.content.pm.ResolveInfo;
41import android.content.pm.Signature;
42import android.content.res.Resources;
43import android.database.ContentObserver;
44import android.hardware.location.ActivityRecognitionHardware;
45import android.location.Address;
46import android.location.Criteria;
47import android.location.GeocoderParams;
48import android.location.Geofence;
49import android.location.IBatchedLocationCallback;
50import android.location.IGnssMeasurementsListener;
51import android.location.IGnssNavigationMessageListener;
52import android.location.IGnssStatusListener;
53import android.location.IGnssStatusProvider;
54import android.location.IGpsGeofenceHardware;
55import android.location.ILocationListener;
56import android.location.ILocationManager;
57import android.location.INetInitiatedListener;
58import android.location.Location;
59import android.location.LocationManager;
Maggieaa080f92018-01-04 15:35:11 -080060import android.location.LocationRequest;
61import android.os.Binder;
62import android.os.Bundle;
63import android.os.Handler;
64import android.os.IBinder;
65import android.os.Looper;
66import android.os.Message;
67import android.os.PowerManager;
68import android.os.Process;
69import android.os.RemoteException;
70import android.os.SystemClock;
71import android.os.UserHandle;
72import android.os.UserManager;
73import android.os.WorkSource;
Narayan Kamath32684dd2018-01-08 17:32:51 +000074import android.os.WorkSource.WorkChain;
Maggieaa080f92018-01-04 15:35:11 -080075import android.provider.Settings;
76import android.text.TextUtils;
Soonil Nagarkar681d7112017-02-23 17:14:16 -080077import android.util.ArrayMap;
Soonil Nagarkar2b565df2017-02-14 13:33:23 -080078import android.util.ArraySet;
Maggieaa080f92018-01-04 15:35:11 -080079import android.util.EventLog;
80import android.util.Log;
81import android.util.Slog;
Yu-Han Yanga4d250e2018-10-02 21:29:20 -070082
destradaaea8a8a62014-06-23 18:19:03 -070083import com.android.internal.content.PackageMonitor;
84import com.android.internal.location.ProviderProperties;
85import com.android.internal.location.ProviderRequest;
86import com.android.internal.os.BackgroundThread;
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -070087import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060088import com.android.internal.util.DumpUtils;
Soonil Nagarkar1575a042018-10-24 17:54:54 -070089import com.android.server.location.AbstractLocationProvider;
destradaaa4fa3b52014-07-09 10:46:39 -070090import com.android.server.location.ActivityRecognitionProxy;
destradaaea8a8a62014-06-23 18:19:03 -070091import com.android.server.location.GeocoderProxy;
92import com.android.server.location.GeofenceManager;
93import com.android.server.location.GeofenceProxy;
Yu-Han Yang3557cc72018-03-21 12:48:36 -070094import com.android.server.location.GnssBatchingProvider;
Lifu Tang818aa2c2016-02-01 01:52:00 -080095import com.android.server.location.GnssLocationProvider;
96import com.android.server.location.GnssMeasurementsProvider;
97import com.android.server.location.GnssNavigationMessageProvider;
destradaaea8a8a62014-06-23 18:19:03 -070098import com.android.server.location.LocationBlacklist;
99import com.android.server.location.LocationFudger;
destradaaea8a8a62014-06-23 18:19:03 -0700100import com.android.server.location.LocationProviderProxy;
101import com.android.server.location.LocationRequestStatistics;
102import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
103import com.android.server.location.LocationRequestStatistics.PackageStatistics;
104import com.android.server.location.MockProvider;
105import com.android.server.location.PassiveProvider;
Yu-Han Yanga4d250e2018-10-02 21:29:20 -0700106
Mike Lockwood43e33f22010-03-26 10:41:48 -0400107import java.io.FileDescriptor;
108import java.io.PrintWriter;
109import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700110import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400111import java.util.HashMap;
112import java.util.HashSet;
113import java.util.List;
114import java.util.Map;
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800115import java.util.Map.Entry;
Wyatt Rileycf879db2017-01-12 13:57:38 -0800116import java.util.NoSuchElementException;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400117import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118
119/**
120 * The service class that manages LocationProviders and issues location
121 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 */
Victoria Lease5cd731a2012-12-19 15:04:21 -0800123public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -0800125 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700126
Olivier Gaillard7a222662017-11-20 16:07:24 +0000127 private static final String WAKELOCK_KEY = "*location*";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128
Victoria Lease37425c32012-10-16 16:08:48 -0700129 // Location resolution level: no location data whatsoever
130 private static final int RESOLUTION_LEVEL_NONE = 0;
131 // Location resolution level: coarse location data only
132 private static final int RESOLUTION_LEVEL_COARSE = 1;
133 // Location resolution level: fine location data
134 private static final int RESOLUTION_LEVEL_FINE = 2;
135
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700137 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400138 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700139 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
140
141 private static final String NETWORK_LOCATION_SERVICE_ACTION =
Stan Chesnutt39062dd2013-07-22 14:33:30 -0700142 "com.android.location.service.v3.NetworkLocationProvider";
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700143 private static final String FUSED_LOCATION_SERVICE_ACTION =
144 "com.android.location.service.FusedLocationProvider";
145
146 private static final int MSG_LOCATION_CHANGED = 1;
147
David Christie1b9b7b12013-04-15 15:31:11 -0700148 private static final long NANOS_PER_MILLI = 1000000L;
149
David Christie0b837452013-07-29 16:02:13 -0700150 // The maximum interval a location request can have and still be considered "high power".
151 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
152
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700153 private static final int FOREGROUND_IMPORTANCE_CUTOFF
gomo48f1a642017-11-10 20:35:46 -0800154 = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700155
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800156 // default background throttling interval if not overriden in settings
Soonil Nagarkarde6780a2017-02-07 10:39:41 -0800157 private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800158
Wei Wangdd070f22018-06-21 11:29:40 -0700159 // Default value for maximum age of last location returned to applications with foreground-only
160 // location permissions.
161 private static final long DEFAULT_LAST_LOCATION_MAX_AGE_MS = 20 * 60 * 1000;
162
Nick Pellyf1be6862012-05-15 10:53:42 -0700163 // Location Providers may sometimes deliver location updates
164 // slightly faster that requested - provide grace period so
165 // we don't unnecessarily filter events that are otherwise on
166 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700167 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700168
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
170
171 private final Context mContext;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800172 private final AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700173
174 // used internally for synchronization
175 private final Object mLock = new Object();
176
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700177 // --- fields below are final after systemRunning() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700178 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700179 private GeofenceManager mGeofenceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700180 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700181 private PowerManager mPowerManager;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800182 private ActivityManager mActivityManager;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700183 private UserManager mUserManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700184 private GeocoderProxy mGeocodeProvider;
Lifu Tang30f95a72016-01-07 23:20:38 -0800185 private IGnssStatusProvider mGnssStatusProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700186 private INetInitiatedListener mNetInitiatedListener;
187 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700188 private PassiveProvider mPassiveProvider; // track passive provider for special cases
189 private LocationBlacklist mBlacklist;
Lifu Tang818aa2c2016-02-01 01:52:00 -0800190 private GnssMeasurementsProvider mGnssMeasurementsProvider;
191 private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
Wei Liu5241a4c2015-05-11 14:00:36 -0700192 private IGpsGeofenceHardware mGpsGeofenceProxy;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700193
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700194 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700196 // Mock (test) providers
197 private final HashMap<String, MockProvider> mMockProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800198 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700200 // all receivers
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800201 private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700203 // currently installed providers (with mocks replacing real providers)
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700204 private final ArrayList<LocationProvider> mProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800205 new ArrayList<>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400206
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700207 // real providers, saved here when mocked out
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700208 private final HashMap<String, LocationProvider> mRealProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800209 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700211 // mapping from provider name to provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700212 private final HashMap<String, LocationProvider> mProvidersByName =
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 all its UpdateRecords
216 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800217 new HashMap<>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700218
David Christie2ff96af2014-01-30 16:09:37 -0800219 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
220
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700221 // mapping from provider name to last known location
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800222 private final HashMap<String, Location> mLastLocation = new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223
David Christie1b9b7b12013-04-15 15:31:11 -0700224 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
225 // locations stored here are not fudged for coarse permissions.
226 private final HashMap<String, Location> mLastLocationCoarseInterval =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800227 new HashMap<>();
David Christie1b9b7b12013-04-15 15:31:11 -0700228
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800229 // all providers that operate over proxy, for authorizing incoming location and whitelisting
230 // throttling
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700231 private final ArrayList<LocationProviderProxy> mProxyProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800232 new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233
Soonil Nagarkar2b565df2017-02-14 13:33:23 -0800234 private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800235
Wyatt Riley11cc7492018-01-17 08:48:27 -0800236 private final ArrayMap<IBinder, Identity> mGnssMeasurementsListeners = new ArrayMap<>();
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800237
Wyatt Riley11cc7492018-01-17 08:48:27 -0800238 private final ArrayMap<IBinder, Identity>
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800239 mGnssNavigationMessageListeners = new ArrayMap<>();
240
Victoria Lease38389b62012-09-30 11:44:22 -0700241 // current active user on the device - other users are denied location data
Xiaohui Chena4490622015-09-22 15:29:31 -0700242 private int mCurrentUserId = UserHandle.USER_SYSTEM;
gomo48f1a642017-11-10 20:35:46 -0800243 private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
Victoria Lease38389b62012-09-30 11:44:22 -0700244
Wei Wangdd070f22018-06-21 11:29:40 -0700245 // Maximum age of last location returned to clients with foreground-only location permissions.
246 private long mLastLocationMaxAgeMs;
247
Lifu Tang9363b942016-02-16 18:07:00 -0800248 private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
Lifu Tang82f893d2016-01-21 18:15:33 -0800249
Siddharth Raybb608c82017-03-16 11:33:34 -0700250 private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
Wyatt Rileyaa420d52017-07-03 15:14:42 -0700251
Yu-Han Yang3557cc72018-03-21 12:48:36 -0700252 private GnssBatchingProvider mGnssBatchingProvider;
Wyatt Rileycf879db2017-01-12 13:57:38 -0800253 private IBatchedLocationCallback mGnssBatchingCallback;
254 private LinkedCallback mGnssBatchingDeathCallback;
255 private boolean mGnssBatchingInProgress = false;
256
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700257 public LocationManagerService(Context context) {
258 super();
259 mContext = context;
gomo48f1a642017-11-10 20:35:46 -0800260 mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800261
Svet Ganovadc1cf42015-06-15 16:36:24 -0700262 // Let the package manager query which are the default location
263 // providers as they get certain permissions granted by default.
264 PackageManagerInternal packageManagerInternal = LocalServices.getService(
265 PackageManagerInternal.class);
266 packageManagerInternal.setLocationPackagesProvider(
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700267 userId -> mContext.getResources().getStringArray(
268 com.android.internal.R.array.config_locationProviderPackageNames));
Svet Ganovadc1cf42015-06-15 16:36:24 -0700269
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700270 if (D) Log.d(TAG, "Constructed");
271
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700272 // most startup is deferred until systemRunning()
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700273 }
274
Svetoslav Ganova0027152013-06-25 14:59:53 -0700275 public void systemRunning() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700276 synchronized (mLock) {
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700277 if (D) Log.d(TAG, "systemRunning()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700278
Victoria Lease5cd731a2012-12-19 15:04:21 -0800279 // fetch package manager
280 mPackageManager = mContext.getPackageManager();
281
Victoria Lease0aa28602013-05-29 15:28:26 -0700282 // fetch power manager
283 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800284
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800285 // fetch activity manager
286 mActivityManager
287 = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
288
Victoria Lease5cd731a2012-12-19 15:04:21 -0800289 // prepare worker thread
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700290 mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
Victoria Lease5cd731a2012-12-19 15:04:21 -0800291
292 // prepare mLocationHandler's dependents
293 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
294 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
295 mBlacklist.init();
296 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
297
Dianne Hackbornc2293022013-02-06 23:14:49 -0800298 // Monitor for app ops mode changes.
Dianne Hackborn9bb0ee92013-09-22 12:31:38 -0700299 AppOpsManager.OnOpChangedListener callback
300 = new AppOpsManager.OnOpChangedInternalListener() {
301 public void onOpChanged(int op, String packageName) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800302 synchronized (mLock) {
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700303 for (Receiver receiver : mReceivers.values()) {
304 receiver.updateMonitoring(true);
305 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800306 applyAllProviderRequirementsLocked();
307 }
308 }
309 };
Wei Wangdd070f22018-06-21 11:29:40 -0700310 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null,
311 AppOpsManager.WATCH_FOREGROUND_CHANGES, callback);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800312
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700313 PackageManager.OnPermissionsChangedListener permissionListener = uid -> {
314 synchronized (mLock) {
315 applyAllProviderRequirementsLocked();
David Christieb870dbf2015-06-22 12:42:53 -0700316 }
317 };
318 mPackageManager.addOnPermissionsChangeListener(permissionListener);
319
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800320 // listen for background/foreground changes
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700321 ActivityManager.OnUidImportanceListener uidImportanceListener =
322 (uid, importance) -> mLocationHandler.post(
323 () -> onUidImportanceChanged(uid, importance));
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800324 mActivityManager.addOnUidImportanceListener(uidImportanceListener,
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700325 FOREGROUND_IMPORTANCE_CUTOFF);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800326
Amith Yamasanib27528d2014-06-05 15:02:10 -0700327 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
328 updateUserProfiles(mCurrentUserId);
329
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800330 updateBackgroundThrottlingWhitelistLocked();
Wei Wangdd070f22018-06-21 11:29:40 -0700331 updateLastLocationMaxAgeLocked();
Soonil Nagarkar2b565df2017-02-14 13:33:23 -0800332
Victoria Lease5cd731a2012-12-19 15:04:21 -0800333 // prepare providers
334 loadProvidersLocked();
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700335 updateProvidersSettingsLocked();
336 for (LocationProvider provider : mProviders) {
337 applyRequirementsLocked(provider.getName());
338 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800339 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700340
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700341 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700342 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700343 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700344 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800345 @Override
346 public void onChange(boolean selfChange) {
347 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700348 updateProvidersSettingsLocked();
Victoria Lease5cd731a2012-12-19 15:04:21 -0800349 }
350 }
351 }, UserHandle.USER_ALL);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800352 mContext.getContentResolver().registerContentObserver(
353 Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS),
354 true,
355 new ContentObserver(mLocationHandler) {
356 @Override
357 public void onChange(boolean selfChange) {
358 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700359 for (LocationProvider provider : mProviders) {
360 applyRequirementsLocked(provider.getName());
361 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800362 }
363 }
364 }, UserHandle.USER_ALL);
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800365 mContext.getContentResolver().registerContentObserver(
Wei Wangdd070f22018-06-21 11:29:40 -0700366 Settings.Global.getUriFor(Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS),
367 true,
368 new ContentObserver(mLocationHandler) {
369 @Override
370 public void onChange(boolean selfChange) {
371 synchronized (mLock) {
372 updateLastLocationMaxAgeLocked();
373 }
374 }
375 }
376 );
377 mContext.getContentResolver().registerContentObserver(
gomo48f1a642017-11-10 20:35:46 -0800378 Settings.Global.getUriFor(
379 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
380 true,
381 new ContentObserver(mLocationHandler) {
382 @Override
383 public void onChange(boolean selfChange) {
384 synchronized (mLock) {
385 updateBackgroundThrottlingWhitelistLocked();
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700386 for (LocationProvider provider : mProviders) {
387 applyRequirementsLocked(provider.getName());
388 }
gomo48f1a642017-11-10 20:35:46 -0800389 }
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800390 }
gomo48f1a642017-11-10 20:35:46 -0800391 }, UserHandle.USER_ALL);
Wei Wangdd070f22018-06-21 11:29:40 -0700392
Victoria Lease5cd731a2012-12-19 15:04:21 -0800393 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700394
Victoria Lease38389b62012-09-30 11:44:22 -0700395 // listen for user change
396 IntentFilter intentFilter = new IntentFilter();
397 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700398 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
399 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
Victoria Lease38389b62012-09-30 11:44:22 -0700400
401 mContext.registerReceiverAsUser(new BroadcastReceiver() {
402 @Override
403 public void onReceive(Context context, Intent intent) {
404 String action = intent.getAction();
405 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
406 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
Amith Yamasanib27528d2014-06-05 15:02:10 -0700407 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
408 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
409 updateUserProfiles(mCurrentUserId);
Victoria Lease38389b62012-09-30 11:44:22 -0700410 }
411 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800412 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700413 }
414
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700415 private void onUidImportanceChanged(int uid, int importance) {
416 boolean foreground = isImportanceForeground(importance);
417 HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
418 synchronized (mLock) {
419 for (Entry<String, ArrayList<UpdateRecord>> entry
gomo48f1a642017-11-10 20:35:46 -0800420 : mRecordsByProvider.entrySet()) {
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700421 String provider = entry.getKey();
422 for (UpdateRecord record : entry.getValue()) {
423 if (record.mReceiver.mIdentity.mUid == uid
gomo48f1a642017-11-10 20:35:46 -0800424 && record.mIsForegroundUid != foreground) {
425 if (D) {
426 Log.d(TAG, "request from uid " + uid + " is now "
427 + (foreground ? "foreground" : "background)"));
428 }
Wyatt Rileyf7075e02018-04-12 17:54:26 -0700429 record.updateForeground(foreground);
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700430
431 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
432 affectedProviders.add(provider);
433 }
434 }
435 }
436 }
437 for (String provider : affectedProviders) {
438 applyRequirementsLocked(provider);
439 }
440
Wyatt Riley11cc7492018-01-17 08:48:27 -0800441 for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700442 if (entry.getValue().mUid == uid) {
gomo48f1a642017-11-10 20:35:46 -0800443 if (D) {
444 Log.d(TAG, "gnss measurements listener from uid " + uid
445 + " is now " + (foreground ? "foreground" : "background)"));
446 }
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700447 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800448 mGnssMeasurementsProvider.addListener(
449 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700450 } else {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800451 mGnssMeasurementsProvider.removeListener(
452 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700453 }
454 }
455 }
456
Wyatt Riley11cc7492018-01-17 08:48:27 -0800457 for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700458 if (entry.getValue().mUid == uid) {
gomo48f1a642017-11-10 20:35:46 -0800459 if (D) {
460 Log.d(TAG, "gnss navigation message listener from uid "
461 + uid + " is now "
462 + (foreground ? "foreground" : "background)"));
463 }
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700464 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800465 mGnssNavigationMessageProvider.addListener(
466 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700467 } else {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800468 mGnssNavigationMessageProvider.removeListener(
469 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700470 }
471 }
472 }
473 }
474 }
475
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800476 private static boolean isImportanceForeground(int importance) {
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700477 return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800478 }
479
Amith Yamasanib27528d2014-06-05 15:02:10 -0700480 /**
481 * Makes a list of userids that are related to the current user. This is
482 * relevant when using managed profiles. Otherwise the list only contains
483 * the current user.
484 *
485 * @param currentUserId the current user, who might have an alter-ego.
486 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700487 private void updateUserProfiles(int currentUserId) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700488 int[] profileIds = mUserManager.getProfileIdsWithDisabled(currentUserId);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700489 synchronized (mLock) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700490 mCurrentUserProfiles = profileIds;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700491 }
492 }
493
494 /**
495 * Checks if the specified userId matches any of the current foreground
496 * users stored in mCurrentUserProfiles.
497 */
498 private boolean isCurrentProfile(int userId) {
499 synchronized (mLock) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700500 return ArrayUtils.contains(mCurrentUserProfiles, userId);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700501 }
502 }
503
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700504 private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) {
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500505 PackageManager pm = mContext.getPackageManager();
506 String systemPackageName = mContext.getPackageName();
507 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
508
509 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
510 new Intent(FUSED_LOCATION_SERVICE_ACTION),
511 PackageManager.GET_META_DATA, mCurrentUserId);
512 for (ResolveInfo rInfo : rInfos) {
513 String packageName = rInfo.serviceInfo.packageName;
514
515 // Check that the signature is in the list of supported sigs. If it's not in
516 // this list the standard provider binding logic won't bind to it.
517 try {
518 PackageInfo pInfo;
519 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
520 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
521 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
522 ", but has wrong signature, ignoring");
523 continue;
524 }
525 } catch (NameNotFoundException e) {
526 Log.e(TAG, "missing package: " + packageName);
527 continue;
528 }
529
530 // Get the version info
531 if (rInfo.serviceInfo.metaData == null) {
532 Log.w(TAG, "Found fused provider without metadata: " + packageName);
533 continue;
534 }
535
536 int version = rInfo.serviceInfo.metaData.getInt(
537 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
538 if (version == 0) {
539 // This should be the fallback fused location provider.
540
541 // Make sure it's in the system partition.
542 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
543 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
544 continue;
545 }
546
547 // Check that the fallback is signed the same as the OS
548 // as a proxy for coreApp="true"
549 if (pm.checkSignatures(systemPackageName, packageName)
550 != PackageManager.SIGNATURE_MATCH) {
gomo48f1a642017-11-10 20:35:46 -0800551 if (D) {
552 Log.d(TAG, "Fallback candidate not signed the same as system: "
553 + packageName);
554 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500555 continue;
556 }
557
558 // Found a valid fallback.
559 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
560 return;
561 } else {
562 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
563 }
564 }
565
566 throw new IllegalStateException("Unable to find a fused location provider that is in the "
567 + "system partition with version 0 and signed with the platform certificate. "
568 + "Such a package is needed to provide a default fused location provider in the "
569 + "event that no other fused location provider has been installed or is currently "
570 + "available. For example, coreOnly boot mode when decrypting the data "
571 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
572 }
573
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700574 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700575 // create a passive location provider, which is always enabled
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700576 LocationProvider passiveProviderManager = new LocationProvider(
577 LocationManager.PASSIVE_PROVIDER);
578 PassiveProvider passiveProvider = new PassiveProvider(passiveProviderManager);
579
580 addProviderLocked(passiveProviderManager);
Victoria Lease5c24fd02012-10-01 11:00:50 -0700581 mPassiveProvider = passiveProvider;
582
Lifu Tang30f95a72016-01-07 23:20:38 -0800583 if (GnssLocationProvider.isSupported()) {
Wei Liu5241a4c2015-05-11 14:00:36 -0700584 // Create a gps location provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700585 LocationProvider gnssProviderManager = new LocationProvider(
586 LocationManager.GPS_PROVIDER);
587 GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext,
588 gnssProviderManager,
Wei Liu5241a4c2015-05-11 14:00:36 -0700589 mLocationHandler.getLooper());
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700590
Lifu Tang9363b942016-02-16 18:07:00 -0800591 mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
Wyatt Rileycf879db2017-01-12 13:57:38 -0800592 mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
Siddharth Raybb608c82017-03-16 11:33:34 -0700593 mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800594 mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
595 mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700596 addProviderLocked(gnssProviderManager);
597 mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProviderManager);
Lifu Tang818aa2c2016-02-01 01:52:00 -0800598 mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
599 mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800600 mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700601 }
602
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700603 /*
604 Load package name(s) containing location provider support.
605 These packages can contain services implementing location providers:
606 Geocoder Provider, Network Location Provider, and
607 Fused Location Provider. They will each be searched for
608 service components implementing these providers.
609 The location framework also has support for installation
610 of new location providers at run-time. The new package does not
611 have to be explicitly listed here, however it must have a signature
612 that matches the signature of at least one package on this list.
613 */
614 Resources resources = mContext.getResources();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500615 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700616 com.android.internal.R.array.config_locationProviderPackageNames);
gomo48f1a642017-11-10 20:35:46 -0800617 if (D) {
618 Log.d(TAG, "certificates for location providers pulled from: " +
619 Arrays.toString(pkgs));
620 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500621
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700622 ensureFallbackFusedProviderPresentLocked(pkgs);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700623
624 // bind to network provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700625
626 LocationProvider networkProviderManager = new LocationProvider(
627 LocationManager.NETWORK_PROVIDER);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700628 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
629 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700630 networkProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700631 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700632 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
633 com.android.internal.R.string.config_networkLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700634 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700635 if (networkProvider != null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700636 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProviderManager);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700637 mProxyProviders.add(networkProvider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700638 addProviderLocked(networkProviderManager);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700639 } else {
gomo48f1a642017-11-10 20:35:46 -0800640 Slog.w(TAG, "no network location provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700641 }
642
643 // bind to fused provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700644 LocationProvider fusedProviderManager = new LocationProvider(
645 LocationManager.FUSED_PROVIDER);
646 LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700647 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700648 fusedProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700649 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700650 com.android.internal.R.bool.config_enableFusedLocationOverlay,
651 com.android.internal.R.string.config_fusedLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700652 com.android.internal.R.array.config_locationProviderPackageNames);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700653 if (fusedProvider != null) {
654 addProviderLocked(fusedProviderManager);
655 mProxyProviders.add(fusedProvider);
656 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedProviderManager);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700657 } else {
658 Slog.e(TAG, "no fused location provider found",
659 new IllegalStateException("Location service needs a fused location provider"));
660 }
661
662 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700663 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
664 com.android.internal.R.bool.config_enableGeocoderOverlay,
665 com.android.internal.R.string.config_geocoderProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700666 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700667 if (mGeocodeProvider == null) {
gomo48f1a642017-11-10 20:35:46 -0800668 Slog.e(TAG, "no geocoder provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700669 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700670
destradaaf9a274c2014-07-25 15:11:56 -0700671 // bind to geofence provider
672 GeofenceProxy provider = GeofenceProxy.createAndBind(
gomo48f1a642017-11-10 20:35:46 -0800673 mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
destradaaf9a274c2014-07-25 15:11:56 -0700674 com.android.internal.R.string.config_geofenceProviderPackageName,
675 com.android.internal.R.array.config_locationProviderPackageNames,
Wei Liu5241a4c2015-05-11 14:00:36 -0700676 mGpsGeofenceProxy,
Jiyong Park4cc3a1c2018-03-08 16:43:07 +0900677 null);
destradaaf9a274c2014-07-25 15:11:56 -0700678 if (provider == null) {
gomo48f1a642017-11-10 20:35:46 -0800679 Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
destradaa0682809a2013-08-12 18:50:30 -0700680 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900681
destradaa6e2fe752015-06-23 17:25:53 -0700682 // bind to hardware activity recognition
683 boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported();
684 ActivityRecognitionHardware activityRecognitionHardware = null;
685 if (activityRecognitionHardwareIsSupported) {
686 activityRecognitionHardware = ActivityRecognitionHardware.getInstance(mContext);
destradaaa4fa3b52014-07-09 10:46:39 -0700687 } else {
destradaa6b4893a2016-05-03 15:33:43 -0700688 Slog.d(TAG, "Hardware Activity-Recognition not supported.");
destradaaa4fa3b52014-07-09 10:46:39 -0700689 }
destradaa6e2fe752015-06-23 17:25:53 -0700690 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
691 mContext,
destradaa6e2fe752015-06-23 17:25:53 -0700692 activityRecognitionHardwareIsSupported,
693 activityRecognitionHardware,
694 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
695 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
696 com.android.internal.R.array.config_locationProviderPackageNames);
697 if (proxy == null) {
destradaa6b4893a2016-05-03 15:33:43 -0700698 Slog.d(TAG, "Unable to bind ActivityRecognitionProxy.");
destradaa6e2fe752015-06-23 17:25:53 -0700699 }
destradaaa4fa3b52014-07-09 10:46:39 -0700700
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900701 String[] testProviderStrings = resources.getStringArray(
702 com.android.internal.R.array.config_testLocationProviders);
703 for (String testProviderString : testProviderStrings) {
704 String fragments[] = testProviderString.split(",");
705 String name = fragments[0].trim();
706 if (mProvidersByName.get(name) != null) {
707 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
708 }
709 ProviderProperties properties = new ProviderProperties(
710 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
711 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
712 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
713 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
714 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
715 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
716 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
717 Integer.parseInt(fragments[8]) /* powerRequirement */,
718 Integer.parseInt(fragments[9]) /* accuracy */);
719 addTestProviderLocked(name, properties);
720 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700721 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700722
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700724 * Called when the device's active user changes.
gomo48f1a642017-11-10 20:35:46 -0800725 *
Victoria Lease38389b62012-09-30 11:44:22 -0700726 * @param userId the new active user's UserId
727 */
728 private void switchUser(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800729 if (mCurrentUserId == userId) {
730 return;
731 }
Victoria Lease83762d22012-10-03 13:51:17 -0700732 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800733 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700734 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700735 mLastLocation.clear();
David Christie1b9b7b12013-04-15 15:31:11 -0700736 mLastLocationCoarseInterval.clear();
Amith Yamasanib27528d2014-06-05 15:02:10 -0700737 updateUserProfiles(userId);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700738 updateProvidersSettingsLocked();
739 mCurrentUserId = userId;
Victoria Lease38389b62012-09-30 11:44:22 -0700740 }
741 }
742
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800743 private static final class Identity {
744 final int mUid;
745 final int mPid;
746 final String mPackageName;
747
748 Identity(int uid, int pid, String packageName) {
749 mUid = uid;
750 mPid = pid;
751 mPackageName = packageName;
752 }
753 }
754
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700755 private class LocationProvider implements AbstractLocationProvider.LocationProviderManager {
756
757 private final String mName;
758 private AbstractLocationProvider mProvider;
759
760 // whether the provider is enabled in location settings
761 private boolean mSettingsEnabled;
762
763 // whether the provider considers itself enabled
764 private volatile boolean mEnabled;
765
766 @Nullable
767 private volatile ProviderProperties mProperties;
768
769 private LocationProvider(String name) {
770 mName = name;
771 // TODO: initialize settings enabled?
772 }
773
774 @Override
775 public void onAttachProvider(AbstractLocationProvider provider, boolean initiallyEnabled) {
776 checkState(mProvider == null);
777
778 // the provider is not yet fully constructed at this point, so we may not do anything
779 // except save a reference for later use here. do not call any provider methods.
780 mProvider = provider;
781 mEnabled = initiallyEnabled;
782 mProperties = null;
783 }
784
785 public String getName() {
786 return mName;
787 }
788
789 public boolean isEnabled() {
790 return mSettingsEnabled && mEnabled;
791 }
792
793 @Nullable
794 public ProviderProperties getProperties() {
795 return mProperties;
796 }
797
798 public void setRequest(ProviderRequest request, WorkSource workSource) {
799 mProvider.setRequest(request, workSource);
800 }
801
802 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
803 pw.println(mName + " provider:");
804 pw.println(" setting=" + mSettingsEnabled);
805 pw.println(" enabled=" + mEnabled);
806 pw.println(" properties=" + mProperties);
807 mProvider.dump(fd, pw, args);
808 }
809
810 public long getStatusUpdateTime() {
811 return mProvider.getStatusUpdateTime();
812 }
813
814 public int getStatus(Bundle extras) {
815 return mProvider.getStatus(extras);
816 }
817
818 public void sendExtraCommand(String command, Bundle extras) {
819 mProvider.sendExtraCommand(command, extras);
820 }
821
822 // called from any thread
823 @Override
824 public void onReportLocation(Location location) {
825 runOnHandler(() -> LocationManagerService.this.reportLocation(location,
826 mProvider == mPassiveProvider));
827 }
828
829 // called from any thread
830 @Override
831 public void onReportLocation(List<Location> locations) {
832 runOnHandler(() -> LocationManagerService.this.reportLocationBatch(locations));
833 }
834
835 // called from any thread
836 @Override
837 public void onSetEnabled(boolean enabled) {
838 runOnHandler(() -> {
839 if (enabled == mEnabled) {
840 return;
841 }
842
843 mEnabled = enabled;
844
845 if (!mSettingsEnabled) {
846 // this provider was disabled in settings anyways, so a change to it's own
847 // enabled status won't have any affect.
848 return;
849 }
850
851 // traditionally clients can listen for changes to the LOCATION_PROVIDERS_ALLOWED
852 // setting to detect when providers are enabled or disabled (even though they aren't
853 // supposed to). to continue to support this we must force a change to this setting.
854 // we use the fused provider because this is forced to be always enabled in settings
855 // anyways, and so won't have any visible effect beyond triggering content observers
856 Settings.Secure.putStringForUser(mContext.getContentResolver(),
857 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
858 "+" + LocationManager.FUSED_PROVIDER, mCurrentUserId);
859 Settings.Secure.putStringForUser(mContext.getContentResolver(),
860 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
861 "-" + LocationManager.FUSED_PROVIDER, mCurrentUserId);
862
863 synchronized (mLock) {
864 if (!enabled) {
865 // If any provider has been disabled, clear all last locations for all
866 // providers. This is to be on the safe side in case a provider has location
867 // derived from this disabled provider.
868 mLastLocation.clear();
869 mLastLocationCoarseInterval.clear();
870 }
871
872 updateProviderListenersLocked(mName);
873 }
874
875 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
876 UserHandle.ALL);
877 });
878 }
879
880 @Override
881 public void onSetProperties(ProviderProperties properties) {
882 runOnHandler(() -> mProperties = properties);
883 }
884
885 private void setSettingsEnabled(boolean enabled) {
886 synchronized (mLock) {
887 if (mSettingsEnabled == enabled) {
888 return;
889 }
890
891 mSettingsEnabled = enabled;
892 if (!mSettingsEnabled) {
893 // if any provider has been disabled, clear all last locations for all
894 // providers. this is to be on the safe side in case a provider has location
895 // derived from this disabled provider.
896 mLastLocation.clear();
897 mLastLocationCoarseInterval.clear();
898 updateProviderListenersLocked(mName);
899 } else if (mEnabled) {
900 updateProviderListenersLocked(mName);
901 }
902 }
903 }
904
905 private void runOnHandler(Runnable runnable) {
906 if (Looper.myLooper() == mLocationHandler.getLooper()) {
907 runnable.run();
908 } else {
909 mLocationHandler.post(runnable);
910 }
911 }
912 }
913
Victoria Lease38389b62012-09-30 11:44:22 -0700914 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
916 * location updates.
917 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700918 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Yu-Han Yang24189822018-07-11 15:24:11 -0700919 private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800920 final Identity mIdentity;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700921 private final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700922
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700923 private final ILocationListener mListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -0700925 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700926 private final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
927 private final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700928
gomo48f1a642017-11-10 20:35:46 -0800929 final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700930
David Christie0b837452013-07-29 16:02:13 -0700931 // True if app ops has started monitoring this receiver for locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700932 private boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -0700933 // True if app ops has started monitoring this receiver for high power (gps) locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700934 private boolean mOpHighPowerMonitoring;
935 private int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -0700936 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700938 private Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -0700939 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700942 if (listener != null) {
943 mKey = listener.asBinder();
944 } else {
945 mKey = intent;
946 }
Victoria Lease37425c32012-10-16 16:08:48 -0700947 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800948 mIdentity = new Identity(uid, pid, packageName);
Narayan Kamath32684dd2018-01-08 17:32:51 +0000949 if (workSource != null && workSource.isEmpty()) {
David Christie82edc9b2013-07-19 11:31:42 -0700950 workSource = null;
951 }
952 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -0700953 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -0700954
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700955 updateMonitoring(true);
956
Victoria Lease0aa28602013-05-29 15:28:26 -0700957 // construct/configure wakelock
958 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -0700959 if (workSource == null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800960 workSource = new WorkSource(mIdentity.mUid, mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -0700961 }
962 mWakeLock.setWorkSource(workSource);
Yu-Han Yang24189822018-07-11 15:24:11 -0700963
964 // For a non-reference counted wakelock, each acquire will reset the timeout, and we
965 // only need to release it once.
966 mWakeLock.setReferenceCounted(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 }
968
969 @Override
970 public boolean equals(Object otherObj) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800971 return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972 }
973
974 @Override
975 public int hashCode() {
976 return mKey.hashCode();
977 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400978
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 @Override
980 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700981 StringBuilder s = new StringBuilder();
982 s.append("Reciever[");
983 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700985 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700987 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700989 for (String p : mUpdateRecords.keySet()) {
990 s.append(" ").append(mUpdateRecords.get(p).toString());
991 }
Wei Wangdd070f22018-06-21 11:29:40 -0700992 s.append(" monitoring location: ").append(mOpMonitoring);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700993 s.append("]");
994 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 }
996
David Christie15b31912013-08-13 15:54:32 -0700997 /**
998 * Update AppOp monitoring for this receiver.
999 *
1000 * @param allow If true receiver is currently active, if false it's been removed.
1001 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001002 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -07001003 if (mHideFromAppOps) {
1004 return;
1005 }
1006
David Christie15b31912013-08-13 15:54:32 -07001007 boolean requestingLocation = false;
1008 boolean requestingHighPowerLocation = false;
1009 if (allow) {
1010 // See if receiver has any enabled update records. Also note if any update records
1011 // are high power (has a high power provider with an interval under a threshold).
1012 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001013 if (isAllowedByUserSettingsLockedForUser(updateRecord.mProvider,
1014 mCurrentUserId)) {
David Christie15b31912013-08-13 15:54:32 -07001015 requestingLocation = true;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001016 LocationManagerService.LocationProvider locationProvider
David Christie2ff96af2014-01-30 16:09:37 -08001017 = mProvidersByName.get(updateRecord.mProvider);
David Christie15b31912013-08-13 15:54:32 -07001018 ProviderProperties properties = locationProvider != null
1019 ? locationProvider.getProperties() : null;
1020 if (properties != null
1021 && properties.mPowerRequirement == Criteria.POWER_HIGH
1022 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
1023 requestingHighPowerLocation = true;
1024 break;
1025 }
1026 }
1027 }
1028 }
1029
David Christie0b837452013-07-29 16:02:13 -07001030 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -07001031 mOpMonitoring = updateMonitoring(
1032 requestingLocation,
1033 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001034 AppOpsManager.OP_MONITOR_LOCATION);
1035
1036 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -07001037 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -07001038 mOpHighPowerMonitoring = updateMonitoring(
1039 requestingHighPowerLocation,
1040 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001041 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -07001042 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -07001043 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -07001044 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
1045 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1046 }
David Christie0b837452013-07-29 16:02:13 -07001047 }
1048
1049 /**
1050 * Update AppOps monitoring for a single location request and op type.
1051 *
gomo48f1a642017-11-10 20:35:46 -08001052 * @param allowMonitoring True if monitoring is allowed for this request/op.
David Christie0b837452013-07-29 16:02:13 -07001053 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
gomo48f1a642017-11-10 20:35:46 -08001054 * @param op AppOps code for the op to update.
David Christie0b837452013-07-29 16:02:13 -07001055 * @return True if monitoring is on for this request/op after updating.
1056 */
1057 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
1058 int op) {
1059 if (!currentlyMonitoring) {
1060 if (allowMonitoring) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001061 return mAppOps.startOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001062 == AppOpsManager.MODE_ALLOWED;
1063 }
1064 } else {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001065 if (!allowMonitoring
Wei Wangdd070f22018-06-21 11:29:40 -07001066 || mAppOps.noteOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001067 != AppOpsManager.MODE_ALLOWED) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001068 mAppOps.finishOp(op, mIdentity.mUid, mIdentity.mPackageName);
David Christie0b837452013-07-29 16:02:13 -07001069 return false;
1070 }
1071 }
1072
1073 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001074 }
1075
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001076 public boolean isListener() {
1077 return mListener != null;
1078 }
1079
1080 public boolean isPendingIntent() {
1081 return mPendingIntent != null;
1082 }
1083
1084 public ILocationListener getListener() {
1085 if (mListener != null) {
1086 return mListener;
1087 }
1088 throw new IllegalStateException("Request for non-existent listener");
1089 }
1090
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
1092 if (mListener != null) {
1093 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001094 synchronized (this) {
1095 // synchronize to ensure incrementPendingBroadcastsLocked()
1096 // is called before decrementPendingBroadcasts()
1097 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -07001098 // call this after broadcasting so we do not increment
1099 // if we throw an exeption.
1100 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001101 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102 } catch (RemoteException e) {
1103 return false;
1104 }
1105 } else {
1106 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -08001107 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
1109 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001110 synchronized (this) {
1111 // synchronize to ensure incrementPendingBroadcastsLocked()
1112 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001113 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001114 getResolutionPermission(mAllowedResolutionLevel),
1115 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001116 // call this after broadcasting so we do not increment
1117 // if we throw an exeption.
1118 incrementPendingBroadcastsLocked();
1119 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 } catch (PendingIntent.CanceledException e) {
1121 return false;
1122 }
1123 }
1124 return true;
1125 }
1126
1127 public boolean callLocationChangedLocked(Location location) {
1128 if (mListener != null) {
1129 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001130 synchronized (this) {
1131 // synchronize to ensure incrementPendingBroadcastsLocked()
1132 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001133 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -07001134 // call this after broadcasting so we do not increment
1135 // if we throw an exeption.
1136 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001137 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001138 } catch (RemoteException e) {
1139 return false;
1140 }
1141 } else {
1142 Intent locationChanged = new Intent();
gomo48f1a642017-11-10 20:35:46 -08001143 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED,
1144 new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001146 synchronized (this) {
1147 // synchronize to ensure incrementPendingBroadcastsLocked()
1148 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001149 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001150 getResolutionPermission(mAllowedResolutionLevel),
1151 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001152 // call this after broadcasting so we do not increment
1153 // if we throw an exeption.
1154 incrementPendingBroadcastsLocked();
1155 }
1156 } catch (PendingIntent.CanceledException e) {
1157 return false;
1158 }
1159 }
1160 return true;
1161 }
1162
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001163 private boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -07001164 // First update AppOp monitoring.
1165 // An app may get/lose location access as providers are enabled/disabled.
1166 updateMonitoring(true);
1167
Mike Lockwood48f17512009-04-23 09:12:08 -07001168 if (mListener != null) {
1169 try {
1170 synchronized (this) {
1171 // synchronize to ensure incrementPendingBroadcastsLocked()
1172 // is called before decrementPendingBroadcasts()
1173 if (enabled) {
1174 mListener.onProviderEnabled(provider);
1175 } else {
1176 mListener.onProviderDisabled(provider);
1177 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001178 // call this after broadcasting so we do not increment
1179 // if we throw an exeption.
1180 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001181 }
1182 } catch (RemoteException e) {
1183 return false;
1184 }
1185 } else {
1186 Intent providerIntent = new Intent();
1187 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
1188 try {
1189 synchronized (this) {
1190 // synchronize to ensure incrementPendingBroadcastsLocked()
1191 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001192 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001193 getResolutionPermission(mAllowedResolutionLevel),
1194 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001195 // call this after broadcasting so we do not increment
1196 // if we throw an exeption.
1197 incrementPendingBroadcastsLocked();
1198 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199 } catch (PendingIntent.CanceledException e) {
1200 return false;
1201 }
1202 }
1203 return true;
1204 }
1205
Nick Pellyf1be6862012-05-15 10:53:42 -07001206 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001207 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001208 if (D) Log.d(TAG, "Location listener died");
1209
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001210 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211 removeUpdatesLocked(this);
1212 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001213 synchronized (this) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001214 clearPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001215 }
1216 }
1217
Nick Pellye0fd6932012-07-11 10:26:13 -07001218 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001219 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1220 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001221 synchronized (this) {
1222 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001223 }
1224 }
1225
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001226 // this must be called while synchronized by caller in a synchronized block
1227 // containing the sending of the broadcaset
1228 private void incrementPendingBroadcastsLocked() {
Yu-Han Yang24189822018-07-11 15:24:11 -07001229 mPendingBroadcasts++;
1230 mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001231 }
1232
1233 private void decrementPendingBroadcastsLocked() {
1234 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001235 if (mWakeLock.isHeld()) {
1236 mWakeLock.release();
1237 }
1238 }
1239 }
1240
1241 public void clearPendingBroadcastsLocked() {
1242 if (mPendingBroadcasts > 0) {
1243 mPendingBroadcasts = 0;
1244 if (mWakeLock.isHeld()) {
1245 mWakeLock.release();
1246 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001247 }
1248 }
1249 }
1250
Nick Pellye0fd6932012-07-11 10:26:13 -07001251 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001252 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001253 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -04001254 //the receiver list if it is not found. If it is not found then the
1255 //LocationListener was removed when it had a pending broadcast and should
1256 //not be added back.
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001257 synchronized (mLock) {
1258 IBinder binder = listener.asBinder();
1259 Receiver receiver = mReceivers.get(binder);
1260 if (receiver != null) {
1261 synchronized (receiver) {
1262 // so wakelock calls will succeed
1263 long identity = Binder.clearCallingIdentity();
1264 receiver.decrementPendingBroadcastsLocked();
1265 Binder.restoreCallingIdentity(identity);
David Christie2ff96af2014-01-30 16:09:37 -08001266 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001267 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 }
1269 }
1270
Lifu Tang82f893d2016-01-21 18:15:33 -08001271 /**
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001272 * Returns the year of the GNSS hardware.
Lifu Tang82f893d2016-01-21 18:15:33 -08001273 */
1274 @Override
Lifu Tang9363b942016-02-16 18:07:00 -08001275 public int getGnssYearOfHardware() {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001276 if (mGnssSystemInfoProvider != null) {
Lifu Tang9363b942016-02-16 18:07:00 -08001277 return mGnssSystemInfoProvider.getGnssYearOfHardware();
Lifu Tang82f893d2016-01-21 18:15:33 -08001278 } else {
1279 return 0;
1280 }
1281 }
1282
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001283
1284 /**
1285 * Returns the model name of the GNSS hardware.
1286 */
1287 @Override
Wyatt Riley49097c02018-03-15 09:14:43 -07001288 @Nullable
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001289 public String getGnssHardwareModelName() {
1290 if (mGnssSystemInfoProvider != null) {
1291 return mGnssSystemInfoProvider.getGnssHardwareModelName();
1292 } else {
Wyatt Riley49097c02018-03-15 09:14:43 -07001293 return null;
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001294 }
1295 }
1296
Wyatt Rileycf879db2017-01-12 13:57:38 -08001297 /**
1298 * Runs some checks for GNSS (FINE) level permissions, used by several methods which directly
1299 * (try to) access GNSS information at this layer.
1300 */
1301 private boolean hasGnssPermissions(String packageName) {
1302 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1303 checkResolutionLevelIsSufficientForProviderUse(
1304 allowedResolutionLevel,
1305 LocationManager.GPS_PROVIDER);
1306
1307 int pid = Binder.getCallingPid();
1308 int uid = Binder.getCallingUid();
1309 long identity = Binder.clearCallingIdentity();
1310 boolean hasLocationAccess;
1311 try {
1312 hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1313 } finally {
1314 Binder.restoreCallingIdentity(identity);
1315 }
1316
1317 return hasLocationAccess;
1318 }
1319
1320 /**
1321 * Returns the GNSS batching size, if available.
1322 */
1323 @Override
1324 public int getGnssBatchSize(String packageName) {
1325 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1326 "Location Hardware permission not granted to access hardware batching");
1327
1328 if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
Yu-Han Yang3557cc72018-03-21 12:48:36 -07001329 return mGnssBatchingProvider.getBatchSize();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001330 } else {
1331 return 0;
1332 }
1333 }
1334
1335 /**
1336 * Adds a callback for GNSS Batching events, if permissions allow, which are transported
1337 * to potentially multiple listeners by the BatchedLocationCallbackTransport above this.
1338 */
1339 @Override
1340 public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
1341 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1342 "Location Hardware permission not granted to access hardware batching");
1343
1344 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1345 return false;
1346 }
1347
1348 mGnssBatchingCallback = callback;
1349 mGnssBatchingDeathCallback = new LinkedCallback(callback);
1350 try {
1351 callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
1352 } catch (RemoteException e) {
1353 // if the remote process registering the listener is already dead, just swallow the
1354 // exception and return
1355 Log.e(TAG, "Remote listener already died.", e);
1356 return false;
1357 }
1358
1359 return true;
1360 }
1361
1362 private class LinkedCallback implements IBinder.DeathRecipient {
1363 private final IBatchedLocationCallback mCallback;
1364
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001365 private LinkedCallback(@NonNull IBatchedLocationCallback callback) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001366 mCallback = callback;
1367 }
1368
1369 @NonNull
1370 public IBatchedLocationCallback getUnderlyingListener() {
1371 return mCallback;
1372 }
1373
1374 @Override
1375 public void binderDied() {
1376 Log.d(TAG, "Remote Batching Callback died: " + mCallback);
1377 stopGnssBatch();
1378 removeGnssBatchingCallback();
1379 }
1380 }
1381
1382 /**
1383 * Removes callback for GNSS batching
1384 */
1385 @Override
1386 public void removeGnssBatchingCallback() {
1387 try {
1388 mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
1389 0 /* flags */);
1390 } catch (NoSuchElementException e) {
1391 // if the death callback isn't connected (it should be...), log error, swallow the
1392 // exception and return
1393 Log.e(TAG, "Couldn't unlink death callback.", e);
1394 }
1395 mGnssBatchingCallback = null;
1396 mGnssBatchingDeathCallback = null;
1397 }
1398
1399
1400 /**
1401 * Starts GNSS batching, if available.
1402 */
1403 @Override
1404 public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
1405 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1406 "Location Hardware permission not granted to access hardware batching");
1407
1408 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1409 return false;
1410 }
1411
1412 if (mGnssBatchingInProgress) {
1413 // Current design does not expect multiple starts to be called repeatedly
1414 Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
1415 // Try to clean up anyway, and continue
1416 stopGnssBatch();
1417 }
1418
1419 mGnssBatchingInProgress = true;
1420 return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
1421 }
1422
1423 /**
1424 * Flushes a GNSS batch in progress
1425 */
1426 @Override
1427 public void flushGnssBatch(String packageName) {
1428 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1429 "Location Hardware permission not granted to access hardware batching");
1430
1431 if (!hasGnssPermissions(packageName)) {
1432 Log.e(TAG, "flushGnssBatch called without GNSS permissions");
1433 return;
1434 }
1435
1436 if (!mGnssBatchingInProgress) {
1437 Log.w(TAG, "flushGnssBatch called with no batch in progress");
1438 }
1439
1440 if (mGnssBatchingProvider != null) {
gomo48f1a642017-11-10 20:35:46 -08001441 mGnssBatchingProvider.flush();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001442 }
1443 }
1444
1445 /**
1446 * Stops GNSS batching
1447 */
1448 @Override
1449 public boolean stopGnssBatch() {
1450 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1451 "Location Hardware permission not granted to access hardware batching");
1452
1453 if (mGnssBatchingProvider != null) {
1454 mGnssBatchingInProgress = false;
1455 return mGnssBatchingProvider.stop();
gomo48f1a642017-11-10 20:35:46 -08001456 } else {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001457 return false;
1458 }
1459 }
1460
1461 @Override
1462 public void reportLocationBatch(List<Location> locations) {
1463 checkCallerIsProvider();
1464
1465 // Currently used only for GNSS locations - update permissions check if changed
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001466 if (isAllowedByUserSettingsLockedForUser(LocationManager.GPS_PROVIDER, mCurrentUserId)) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001467 if (mGnssBatchingCallback == null) {
1468 Slog.e(TAG, "reportLocationBatch() called without active Callback");
1469 return;
1470 }
1471 try {
1472 mGnssBatchingCallback.onLocationBatch(locations);
1473 } catch (RemoteException e) {
1474 Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
1475 }
1476 } else {
1477 Slog.w(TAG, "reportLocationBatch() called without user permission, locations blocked");
1478 }
1479 }
1480
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001481 private void addProviderLocked(LocationProvider provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001482 mProviders.add(provider);
1483 mProvidersByName.put(provider.getName(), provider);
1484 }
1485
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001486 private void removeProviderLocked(LocationProvider provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001487 mProviders.remove(provider);
1488 mProvidersByName.remove(provider.getName());
1489 }
1490
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001491 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -08001492 * Returns "true" if access to the specified location provider is allowed by the specified
1493 * user's settings. Access to all location providers is forbidden to non-location-provider
1494 * processes belonging to background users.
1495 *
1496 * @param provider the name of the location provider
Maggie2a9409e2018-03-21 11:47:28 -07001497 * @param userId the user id to query
Victoria Lease09eeaec2013-02-05 11:34:13 -08001498 */
Maggie2a9409e2018-03-21 11:47:28 -07001499 private boolean isAllowedByUserSettingsLockedForUser(String provider, int userId) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001500 if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1501 return isLocationEnabledForUser(userId);
Maggie2a9409e2018-03-21 11:47:28 -07001502 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001503 if (LocationManager.FUSED_PROVIDER.equals(provider)) {
1504 return isLocationEnabledForUser(userId);
Maggie2a9409e2018-03-21 11:47:28 -07001505 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001506 synchronized (mLock) {
1507 if (mMockProviders.containsKey(provider)) {
1508 return isLocationEnabledForUser(userId);
1509 }
1510 }
1511
1512 long identity = Binder.clearCallingIdentity();
1513 try {
1514 // Use system settings
1515 ContentResolver cr = mContext.getContentResolver();
1516 String allowedProviders = Settings.Secure.getStringForUser(
1517 cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId);
1518 return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
1519 } finally {
1520 Binder.restoreCallingIdentity(identity);
1521 }
Maggie2a9409e2018-03-21 11:47:28 -07001522 }
1523
1524
1525 /**
1526 * Returns "true" if access to the specified location provider is allowed by the specified
1527 * user's settings. Access to all location providers is forbidden to non-location-provider
1528 * processes belonging to background users.
1529 *
1530 * @param provider the name of the location provider
1531 * @param uid the requestor's UID
1532 * @param userId the user id to query
1533 */
1534 private boolean isAllowedByUserSettingsLocked(String provider, int uid, int userId) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001535 if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001536 return false;
1537 }
Maggie2a9409e2018-03-21 11:47:28 -07001538 return isAllowedByUserSettingsLockedForUser(provider, userId);
Victoria Lease09eeaec2013-02-05 11:34:13 -08001539 }
1540
1541 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001542 * Returns the permission string associated with the specified resolution level.
1543 *
1544 * @param resolutionLevel the resolution level
1545 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001546 */
Victoria Lease37425c32012-10-16 16:08:48 -07001547 private String getResolutionPermission(int resolutionLevel) {
1548 switch (resolutionLevel) {
1549 case RESOLUTION_LEVEL_FINE:
1550 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1551 case RESOLUTION_LEVEL_COARSE:
1552 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1553 default:
1554 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001555 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001556 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001557
Victoria Leaseda479c52012-10-15 15:24:16 -07001558 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001559 * Returns the resolution level allowed to the given PID/UID pair.
1560 *
1561 * @param pid the PID
1562 * @param uid the UID
1563 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -07001564 */
Victoria Lease37425c32012-10-16 16:08:48 -07001565 private int getAllowedResolutionLevel(int pid, int uid) {
1566 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001567 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001568 return RESOLUTION_LEVEL_FINE;
1569 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001570 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001571 return RESOLUTION_LEVEL_COARSE;
1572 } else {
1573 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001574 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001575 }
1576
1577 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001578 * Returns the resolution level allowed to the caller
1579 *
1580 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -07001581 */
Victoria Lease37425c32012-10-16 16:08:48 -07001582 private int getCallerAllowedResolutionLevel() {
1583 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1584 }
1585
1586 /**
1587 * Throw SecurityException if specified resolution level is insufficient to use geofences.
1588 *
1589 * @param allowedResolutionLevel resolution level allowed to caller
1590 */
1591 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1592 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001593 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1594 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001595 }
1596
Victoria Lease37425c32012-10-16 16:08:48 -07001597 /**
1598 * Return the minimum resolution level required to use the specified location provider.
1599 *
1600 * @param provider the name of the location provider
1601 * @return minimum resolution level required for provider
1602 */
1603 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001604 if (LocationManager.GPS_PROVIDER.equals(provider) ||
1605 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1606 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001607 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -07001608 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1609 LocationManager.FUSED_PROVIDER.equals(provider)) {
1610 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001611 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001612 } else {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001613 for (LocationProvider lp : mProviders) {
1614 if (!lp.getName().equals(provider)) {
1615 continue;
1616 }
1617
Laurent Tu941221c2012-10-04 14:21:52 -07001618 ProviderProperties properties = lp.getProperties();
1619 if (properties != null) {
1620 if (properties.mRequiresSatellite) {
1621 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001622 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001623 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1624 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001625 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001626 }
1627 }
1628 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001629 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001630
Victoria Lease37425c32012-10-16 16:08:48 -07001631 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001632 }
1633
Victoria Lease37425c32012-10-16 16:08:48 -07001634 /**
1635 * Throw SecurityException if specified resolution level is insufficient to use the named
1636 * location provider.
1637 *
1638 * @param allowedResolutionLevel resolution level allowed to caller
gomo48f1a642017-11-10 20:35:46 -08001639 * @param providerName the name of the location provider
Victoria Lease37425c32012-10-16 16:08:48 -07001640 */
1641 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1642 String providerName) {
1643 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1644 if (allowedResolutionLevel < requiredResolutionLevel) {
1645 switch (requiredResolutionLevel) {
1646 case RESOLUTION_LEVEL_FINE:
1647 throw new SecurityException("\"" + providerName + "\" location provider " +
1648 "requires ACCESS_FINE_LOCATION permission.");
1649 case RESOLUTION_LEVEL_COARSE:
1650 throw new SecurityException("\"" + providerName + "\" location provider " +
1651 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1652 default:
1653 throw new SecurityException("Insufficient permission for \"" + providerName +
1654 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001655 }
1656 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001657 }
1658
David Christie82edc9b2013-07-19 11:31:42 -07001659 /**
1660 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
1661 * for battery).
1662 */
David Christie40e57822013-07-30 11:36:48 -07001663 private void checkDeviceStatsAllowed() {
David Christie82edc9b2013-07-19 11:31:42 -07001664 mContext.enforceCallingOrSelfPermission(
1665 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
1666 }
1667
David Christie40e57822013-07-30 11:36:48 -07001668 private void checkUpdateAppOpsAllowed() {
1669 mContext.enforceCallingOrSelfPermission(
1670 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
1671 }
1672
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001673 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001674 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1675 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001676 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001677 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001678 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001679 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001680 }
1681 return -1;
1682 }
1683
Wei Wangb86334f2018-07-03 16:33:24 -07001684 private static String resolutionLevelToOpStr(int allowedResolutionLevel) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001685 switch (allowedResolutionLevel) {
Wei Wangb86334f2018-07-03 16:33:24 -07001686 case RESOLUTION_LEVEL_COARSE:
1687 return AppOpsManager.OPSTR_COARSE_LOCATION;
1688 case RESOLUTION_LEVEL_FINE:
1689 return AppOpsManager.OPSTR_FINE_LOCATION;
1690 case RESOLUTION_LEVEL_NONE:
1691 // The client is not allowed to get any location, so both FINE and COARSE ops will
1692 // be denied. Pick the most restrictive one to be safe.
1693 return AppOpsManager.OPSTR_FINE_LOCATION;
1694 default:
1695 // Use the most restrictive ops if not sure.
1696 return AppOpsManager.OPSTR_FINE_LOCATION;
1697 }
1698 }
1699
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001700 private boolean reportLocationAccessNoThrow(
David Christieb870dbf2015-06-22 12:42:53 -07001701 int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001702 int op = resolutionLevelToOp(allowedResolutionLevel);
1703 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001704 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1705 return false;
1706 }
1707 }
David Christieb870dbf2015-06-22 12:42:53 -07001708
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001709 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001710 }
1711
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001712 private boolean checkLocationAccess(int pid, int uid, String packageName,
1713 int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001714 int op = resolutionLevelToOp(allowedResolutionLevel);
1715 if (op >= 0) {
Wei Wangdd070f22018-06-21 11:29:40 -07001716 if (mAppOps.noteOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001717 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
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001724 /**
Maggie91e630c2018-01-24 17:31:46 -08001725 * Returns all providers by name, including passive and the ones that are not permitted to
1726 * be accessed by the calling activity or are currently disabled, but excluding fused.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001727 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001728 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 public List<String> getAllProviders() {
Maggie91e630c2018-01-24 17:31:46 -08001730 ArrayList<String> out;
1731 synchronized (mLock) {
1732 out = new ArrayList<>(mProviders.size());
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001733 for (LocationProvider provider : mProviders) {
Maggie91e630c2018-01-24 17:31:46 -08001734 String name = provider.getName();
1735 if (LocationManager.FUSED_PROVIDER.equals(name)) {
1736 continue;
1737 }
1738 out.add(name);
1739 }
1740 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001741 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 return out;
1743 }
1744
Mike Lockwood03ca2162010-04-01 08:10:09 -07001745 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001746 * Return all providers by name, that match criteria and are optionally
1747 * enabled.
1748 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001749 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001750 @Override
1751 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001752 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001753 ArrayList<String> out;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001754 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07001755 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001756 try {
1757 synchronized (mLock) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001758 out = new ArrayList<>(mProviders.size());
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001759 for (LocationProvider provider : mProviders) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001760 String name = provider.getName();
1761 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001762 continue;
1763 }
Victoria Lease37425c32012-10-16 16:08:48 -07001764 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Maggie2a9409e2018-03-21 11:47:28 -07001765 if (enabledOnly
1766 && !isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001767 continue;
1768 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001769 if (criteria != null
1770 && !android.location.LocationProvider.propertiesMeetCriteria(
Victoria Leaseb711d572012-10-02 13:14:11 -07001771 name, provider.getProperties(), criteria)) {
1772 continue;
1773 }
1774 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001775 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001776 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001777 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001778 } finally {
1779 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001780 }
1781
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001782 if (D) Log.d(TAG, "getProviders()=" + out);
1783 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001784 }
1785
1786 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001787 * Return the name of the best provider given a Criteria object.
1788 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001789 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001790 * has been deprecated as well. So this method now uses
1791 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001792 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001793 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001794 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001795 String result;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001796
1797 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001798 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001799 result = pickBest(providers);
1800 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1801 return result;
1802 }
1803 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001804 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001805 result = pickBest(providers);
1806 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1807 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001808 }
1809
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001810 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + null);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001811 return null;
1812 }
1813
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001814 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -07001815 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001816 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -07001817 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1818 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001819 } else {
1820 return providers.get(0);
1821 }
1822 }
1823
Nick Pellye0fd6932012-07-11 10:26:13 -07001824 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001825 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001826 LocationProvider p = mProvidersByName.get(provider);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001827 if (p == null) {
1828 throw new IllegalArgumentException("provider=" + provider);
1829 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001830
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001831 boolean result = android.location.LocationProvider.propertiesMeetCriteria(
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001832 p.getName(), p.getProperties(), criteria);
1833 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1834 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001835 }
1836
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001837 private void updateProvidersSettingsLocked() {
1838 for (LocationProvider p : mProviders) {
1839 p.setSettingsEnabled(isAllowedByUserSettingsLockedForUser(p.getName(), mCurrentUserId));
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001840 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001841
1842 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1843 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001844 }
1845
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001846 private void updateProviderListenersLocked(String provider) {
1847 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001848 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001849
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001850 boolean enabled = p.isEnabled();
1851
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001852 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001853
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001854 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1855 if (records != null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001856 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001857 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001858 // Sends a notification message to the receiver
1859 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1860 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001861 deadReceivers = new ArrayList<>();
Victoria Leaseb711d572012-10-02 13:14:11 -07001862 }
1863 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001864 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001865 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001866 }
1867 }
1868
1869 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001870 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001871 removeUpdatesLocked(deadReceivers.get(i));
1872 }
1873 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001874
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001875 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 }
1877
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001878 private void applyRequirementsLocked(String provider) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001879 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001880 if (p == null) return;
1881
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001882 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001883 WorkSource worksource = new WorkSource();
1884 ProviderRequest providerRequest = new ProviderRequest();
1885
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001886 ContentResolver resolver = mContext.getContentResolver();
1887 long backgroundThrottleInterval = Settings.Global.getLong(
1888 resolver,
1889 Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
1890 DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
1891
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001892 if (p.isEnabled() && records != null && !records.isEmpty()) {
1893 // initialize the low power mode to true and set to false if any of the records requires
1894 providerRequest.lowPowerMode = true;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001895 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001896 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
David Christieb870dbf2015-06-22 12:42:53 -07001897 if (checkLocationAccess(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001898 record.mReceiver.mIdentity.mPid,
1899 record.mReceiver.mIdentity.mUid,
1900 record.mReceiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001901 record.mReceiver.mAllowedResolutionLevel)) {
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001902 LocationRequest locationRequest = record.mRealRequest;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001903 long interval = locationRequest.getInterval();
1904
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001905 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001906 if (!record.mIsForegroundUid) {
1907 interval = Math.max(interval, backgroundThrottleInterval);
1908 }
1909 if (interval != locationRequest.getInterval()) {
1910 locationRequest = new LocationRequest(locationRequest);
1911 locationRequest.setInterval(interval);
1912 }
1913 }
1914
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001915 record.mRequest = locationRequest;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001916 providerRequest.locationRequests.add(locationRequest);
gomo48f1a642017-11-10 20:35:46 -08001917 if (!locationRequest.isLowPowerMode()) {
1918 providerRequest.lowPowerMode = false;
1919 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001920 if (interval < providerRequest.interval) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001921 providerRequest.reportLocation = true;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001922 providerRequest.interval = interval;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001923 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001924 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001925 }
1926 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001927
1928 if (providerRequest.reportLocation) {
1929 // calculate who to blame for power
1930 // This is somewhat arbitrary. We pick a threshold interval
1931 // that is slightly higher that the minimum interval, and
1932 // spread the blame across all applications with a request
1933 // under that threshold.
1934 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1935 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001936 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001937 LocationRequest locationRequest = record.mRequest;
Svet Ganove998c732016-06-10 00:12:38 -07001938
1939 // Don't assign battery blame for update records whose
1940 // client has no permission to receive location data.
1941 if (!providerRequest.locationRequests.contains(locationRequest)) {
1942 continue;
1943 }
1944
Victoria Leaseb711d572012-10-02 13:14:11 -07001945 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07001946 if (record.mReceiver.mWorkSource != null
Narayan Kamath32684dd2018-01-08 17:32:51 +00001947 && isValidWorkSource(record.mReceiver.mWorkSource)) {
David Christie82edc9b2013-07-19 11:31:42 -07001948 worksource.add(record.mReceiver.mWorkSource);
1949 } else {
Narayan Kamath32684dd2018-01-08 17:32:51 +00001950 // Assign blame to caller if there's no WorkSource associated with
1951 // the request or if it's invalid.
David Christie82edc9b2013-07-19 11:31:42 -07001952 worksource.add(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001953 record.mReceiver.mIdentity.mUid,
1954 record.mReceiver.mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07001955 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001956 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001957 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001958 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001959 }
1960 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001961
1962 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1963 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001964 }
1965
Narayan Kamath32684dd2018-01-08 17:32:51 +00001966 /**
1967 * Whether a given {@code WorkSource} associated with a Location request is valid.
1968 */
1969 private static boolean isValidWorkSource(WorkSource workSource) {
1970 if (workSource.size() > 0) {
1971 // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
1972 // by tags.
1973 return workSource.getName(0) != null;
1974 } else {
1975 // For now, make sure callers have supplied an attribution tag for use with
1976 // AppOpsManager. This might be relaxed in the future.
1977 final ArrayList<WorkChain> workChains = workSource.getWorkChains();
1978 return workChains != null && !workChains.isEmpty() &&
1979 workChains.get(0).getAttributionTag() != null;
1980 }
1981 }
1982
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001983 @Override
1984 public String[] getBackgroundThrottlingWhitelist() {
1985 synchronized (mLock) {
1986 return mBackgroundThrottlePackageWhitelist.toArray(
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001987 new String[0]);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001988 }
1989 }
1990
1991 private void updateBackgroundThrottlingWhitelistLocked() {
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08001992 String setting = Settings.Global.getString(
gomo48f1a642017-11-10 20:35:46 -08001993 mContext.getContentResolver(),
1994 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08001995 if (setting == null) {
1996 setting = "";
1997 }
1998
1999 mBackgroundThrottlePackageWhitelist.clear();
2000 mBackgroundThrottlePackageWhitelist.addAll(
gomo48f1a642017-11-10 20:35:46 -08002001 SystemConfig.getInstance().getAllowUnthrottledLocation());
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08002002 mBackgroundThrottlePackageWhitelist.addAll(
gomo48f1a642017-11-10 20:35:46 -08002003 Arrays.asList(setting.split(",")));
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08002004 }
2005
Wei Wangdd070f22018-06-21 11:29:40 -07002006 private void updateLastLocationMaxAgeLocked() {
2007 mLastLocationMaxAgeMs =
2008 Settings.Global.getLong(
2009 mContext.getContentResolver(),
2010 Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
2011 DEFAULT_LAST_LOCATION_MAX_AGE_MS);
2012 }
2013
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002014 private boolean isThrottlingExemptLocked(Identity identity) {
2015 if (identity.mUid == Process.SYSTEM_UID) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002016 return true;
2017 }
2018
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002019 if (mBackgroundThrottlePackageWhitelist.contains(identity.mPackageName)) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002020 return true;
2021 }
2022
2023 for (LocationProviderProxy provider : mProxyProviders) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002024 if (identity.mPackageName.equals(provider.getConnectedPackageName())) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002025 return true;
2026 }
2027 }
2028
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002029 return false;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002030 }
2031
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002032 private class UpdateRecord {
2033 final String mProvider;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002034 private final LocationRequest mRealRequest; // original request from client
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002035 LocationRequest mRequest; // possibly throttled version of the request
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002036 private final Receiver mReceiver;
2037 private boolean mIsForegroundUid;
2038 private Location mLastFixBroadcast;
2039 private long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002040
2041 /**
2042 * Note: must be constructed with lock held.
2043 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002044 private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002045 mProvider = provider;
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002046 mRealRequest = request;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002047 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002048 mReceiver = receiver;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002049 mIsForegroundUid = isImportanceForeground(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002050 mActivityManager.getPackageImportance(mReceiver.mIdentity.mPackageName));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002051
2052 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2053 if (records == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002054 records = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002055 mRecordsByProvider.put(provider, records);
2056 }
2057 if (!records.contains(this)) {
2058 records.add(this);
2059 }
David Christie2ff96af2014-01-30 16:09:37 -08002060
2061 // Update statistics for historical location requests by package/provider
2062 mRequestStatistics.startRequesting(
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002063 mReceiver.mIdentity.mPackageName, provider, request.getInterval(),
2064 mIsForegroundUid);
2065 }
2066
2067 /**
2068 * Method to be called when record changes foreground/background
2069 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002070 private void updateForeground(boolean isForeground) {
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002071 mIsForegroundUid = isForeground;
2072 mRequestStatistics.updateForeground(
2073 mReceiver.mIdentity.mPackageName, mProvider, isForeground);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002074 }
2075
2076 /**
David Christie2ff96af2014-01-30 16:09:37 -08002077 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002078 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002079 private void disposeLocked(boolean removeReceiver) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002080 mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
David Christie2ff96af2014-01-30 16:09:37 -08002081
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002082 // remove from mRecordsByProvider
2083 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
2084 if (globalRecords != null) {
2085 globalRecords.remove(this);
2086 }
2087
2088 if (!removeReceiver) return; // the caller will handle the rest
2089
2090 // remove from Receiver#mUpdateRecords
2091 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002092 receiverRecords.remove(this.mProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002093
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002094 // and also remove the Receiver if it has no more update records
2095 if (receiverRecords.size() == 0) {
2096 removeUpdatesLocked(mReceiver);
Mike Lockwood3a76fd62009-09-01 07:26:56 -04002097 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002098 }
2099
2100 @Override
2101 public String toString() {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002102 return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
gomo48f1a642017-11-10 20:35:46 -08002103 + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground"
2104 : " background")
Wyatt Riley19adc022018-05-22 13:30:51 -07002105 + ")" + " " + mRealRequest + " "
2106 + mReceiver.mWorkSource + "]";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002107 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002108 }
2109
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002110 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07002111 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002112 IBinder binder = listener.asBinder();
2113 Receiver receiver = mReceivers.get(binder);
2114 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002115 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
2116 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002117 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002118 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002119 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002120 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002121 return null;
2122 }
Wen Jingcb3ab222014-03-27 13:42:59 +08002123 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002124 }
2125 return receiver;
2126 }
2127
David Christie82edc9b2013-07-19 11:31:42 -07002128 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07002129 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002130 Receiver receiver = mReceivers.get(intent);
2131 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002132 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
2133 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002134 mReceivers.put(intent, receiver);
2135 }
2136 return receiver;
2137 }
2138
Victoria Lease37425c32012-10-16 16:08:48 -07002139 /**
2140 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
2141 * and consistency requirements.
2142 *
2143 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07002144 * @return a version of request that meets the given resolution and consistency requirements
2145 * @hide
2146 */
gomo48f1a642017-11-10 20:35:46 -08002147 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel,
2148 boolean callerHasLocationHardwarePermission) {
Victoria Lease37425c32012-10-16 16:08:48 -07002149 LocationRequest sanitizedRequest = new LocationRequest(request);
gomo48f1a642017-11-10 20:35:46 -08002150 if (!callerHasLocationHardwarePermission) {
2151 // allow setting low power mode only for callers with location hardware permission
2152 sanitizedRequest.setLowPowerMode(false);
2153 }
Victoria Lease37425c32012-10-16 16:08:48 -07002154 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
2155 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002156 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07002157 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07002158 break;
2159 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07002160 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07002161 break;
2162 }
2163 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07002164 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2165 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002166 }
Victoria Lease37425c32012-10-16 16:08:48 -07002167 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2168 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002169 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002170 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002171 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07002172 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002173 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002174 }
Victoria Lease37425c32012-10-16 16:08:48 -07002175 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002176 }
2177
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002178 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07002179 if (packageName == null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002180 throw new SecurityException("invalid package name: " + null);
Nick Pellye0fd6932012-07-11 10:26:13 -07002181 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002182 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07002183 String[] packages = mPackageManager.getPackagesForUid(uid);
2184 if (packages == null) {
2185 throw new SecurityException("invalid UID " + uid);
2186 }
2187 for (String pkg : packages) {
2188 if (packageName.equals(pkg)) return;
2189 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002190 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002191 }
2192
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002193 private void checkPendingIntent(PendingIntent intent) {
2194 if (intent == null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002195 throw new IllegalArgumentException("invalid pending intent: " + null);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07002196 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002197 }
2198
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002199 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
David Christie40e57822013-07-30 11:36:48 -07002200 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002201 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002202 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002203 } else if (intent != null && listener != null) {
2204 throw new IllegalArgumentException("cannot register both listener and intent");
2205 } else if (intent != null) {
2206 checkPendingIntent(intent);
David Christie40e57822013-07-30 11:36:48 -07002207 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002208 } else {
David Christie40e57822013-07-30 11:36:48 -07002209 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002210 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07002211 }
2212
Nick Pellye0fd6932012-07-11 10:26:13 -07002213 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002214 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
2215 PendingIntent intent, String packageName) {
2216 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2217 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002218 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2219 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2220 request.getProvider());
David Christie82edc9b2013-07-19 11:31:42 -07002221 WorkSource workSource = request.getWorkSource();
Narayan Kamath32684dd2018-01-08 17:32:51 +00002222 if (workSource != null && !workSource.isEmpty()) {
David Christie40e57822013-07-30 11:36:48 -07002223 checkDeviceStatsAllowed();
2224 }
2225 boolean hideFromAppOps = request.getHideFromAppOps();
2226 if (hideFromAppOps) {
2227 checkUpdateAppOpsAllowed();
David Christie82edc9b2013-07-19 11:31:42 -07002228 }
gomo48f1a642017-11-10 20:35:46 -08002229 boolean callerHasLocationHardwarePermission =
2230 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
Maggieaa080f92018-01-04 15:35:11 -08002231 == PERMISSION_GRANTED;
gomo48f1a642017-11-10 20:35:46 -08002232 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
2233 callerHasLocationHardwarePermission);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002234
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002235 final int pid = Binder.getCallingPid();
2236 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002237 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002238 long identity = Binder.clearCallingIdentity();
2239 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002240 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
2241 // a location.
David Christieb870dbf2015-06-22 12:42:53 -07002242 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002243
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002244 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002245 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
David Christie40e57822013-07-30 11:36:48 -07002246 packageName, workSource, hideFromAppOps);
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002247 requestLocationUpdatesLocked(sanitizedRequest, recevier, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04002248 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002249 } finally {
2250 Binder.restoreCallingIdentity(identity);
2251 }
2252 }
2253
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002254 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002255 int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002256 // Figure out the provider. Either its explicitly request (legacy use cases), or
2257 // use the fused provider
2258 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2259 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07002260 if (name == null) {
2261 throw new IllegalArgumentException("provider name must not be null");
2262 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07002263
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002264 LocationProvider provider = mProvidersByName.get(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002265 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07002266 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002267 }
2268
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002269 UpdateRecord record = new UpdateRecord(name, request, receiver);
gomo48f1a642017-11-10 20:35:46 -08002270 if (D) {
2271 Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
2272 + " " + name + " " + request + " from " + packageName + "(" + uid + " "
2273 + (record.mIsForegroundUid ? "foreground" : "background")
2274 + (isThrottlingExemptLocked(receiver.mIdentity)
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002275 ? " [whitelisted]" : "") + ")");
gomo48f1a642017-11-10 20:35:46 -08002276 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002277
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002278 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
2279 if (oldRecord != null) {
2280 oldRecord.disposeLocked(false);
2281 }
2282
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002283 if (provider.isEnabled()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002284 applyRequirementsLocked(name);
2285 } else {
2286 // Notify the listener that updates are currently disabled
2287 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002288 }
David Christie0b837452013-07-29 16:02:13 -07002289 // Update the monitoring here just in case multiple location requests were added to the
2290 // same receiver (this request may be high power and the initial might not have been).
2291 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002292 }
2293
Nick Pellye0fd6932012-07-11 10:26:13 -07002294 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002295 public void removeUpdates(ILocationListener listener, PendingIntent intent,
2296 String packageName) {
2297 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002298
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002299 final int pid = Binder.getCallingPid();
2300 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002301
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002302 synchronized (mLock) {
David Christie40e57822013-07-30 11:36:48 -07002303 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002304 packageName, null, false);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002305
2306 // providers may use public location API's, need to clear identity
2307 long identity = Binder.clearCallingIdentity();
2308 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002309 removeUpdatesLocked(receiver);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002310 } finally {
2311 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002312 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002313 }
2314 }
2315
2316 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08002317 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002318
2319 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
2320 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
2321 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07002322 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002323 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002324 }
2325
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07002326 receiver.updateMonitoring(false);
2327
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002328 // Record which providers were associated with this listener
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002329 HashSet<String> providers = new HashSet<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002330 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
2331 if (oldRecords != null) {
2332 // Call dispose() on the obsolete update records.
2333 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08002334 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002335 record.disposeLocked(false);
2336 }
2337 // Accumulate providers
2338 providers.addAll(oldRecords.keySet());
2339 }
2340
2341 // update provider
2342 for (String provider : providers) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002343 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002344 }
2345 }
2346
Dianne Hackbornc2293022013-02-06 23:14:49 -08002347 private void applyAllProviderRequirementsLocked() {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002348 for (LocationProvider p : mProviders) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08002349 applyRequirementsLocked(p.getName());
2350 }
2351 }
2352
Nick Pellye0fd6932012-07-11 10:26:13 -07002353 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07002354 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002355 if (D) Log.d(TAG, "getLastLocation: " + request);
2356 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002357 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07002358 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002359 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2360 request.getProvider());
2361 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07002362
David Christieb870dbf2015-06-22 12:42:53 -07002363 final int pid = Binder.getCallingPid();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002364 final int uid = Binder.getCallingUid();
2365 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07002366 try {
2367 if (mBlacklist.isBlacklisted(packageName)) {
gomo48f1a642017-11-10 20:35:46 -08002368 if (D) {
2369 Log.d(TAG, "not returning last loc for blacklisted app: " +
2370 packageName);
2371 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002372 return null;
2373 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002374
David Christieb870dbf2015-06-22 12:42:53 -07002375 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08002376 if (D) {
2377 Log.d(TAG, "not returning last loc for no op app: " +
2378 packageName);
2379 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002380 return null;
2381 }
2382
Victoria Leaseb711d572012-10-02 13:14:11 -07002383 synchronized (mLock) {
2384 // Figure out the provider. Either its explicitly request (deprecated API's),
2385 // or use the fused provider
2386 String name = request.getProvider();
2387 if (name == null) name = LocationManager.FUSED_PROVIDER;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002388 LocationProvider provider = mProvidersByName.get(name);
Victoria Leaseb711d572012-10-02 13:14:11 -07002389 if (provider == null) return null;
2390
Maggie2a9409e2018-03-21 11:47:28 -07002391 if (!isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07002392
David Christie1b9b7b12013-04-15 15:31:11 -07002393 Location location;
2394 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2395 // Make sure that an app with coarse permissions can't get frequent location
2396 // updates by calling LocationManager.getLastKnownLocation repeatedly.
2397 location = mLastLocationCoarseInterval.get(name);
2398 } else {
2399 location = mLastLocation.get(name);
2400 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002401 if (location == null) {
2402 return null;
2403 }
Wei Wangdd070f22018-06-21 11:29:40 -07002404
2405 // Don't return stale location to apps with foreground-only location permission.
Wei Wangb86334f2018-07-03 16:33:24 -07002406 String op = resolutionLevelToOpStr(allowedResolutionLevel);
Wei Wangdd070f22018-06-21 11:29:40 -07002407 long locationAgeMs = SystemClock.elapsedRealtime() -
2408 location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
2409 if ((locationAgeMs > mLastLocationMaxAgeMs)
2410 && (mAppOps.unsafeCheckOp(op, uid, packageName)
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002411 == AppOpsManager.MODE_FOREGROUND)) {
Wei Wangdd070f22018-06-21 11:29:40 -07002412 return null;
2413 }
2414
Victoria Lease37425c32012-10-16 16:08:48 -07002415 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
gomo48f1a642017-11-10 20:35:46 -08002416 Location noGPSLocation = location.getExtraLocation(
2417 Location.EXTRA_NO_GPS_LOCATION);
Victoria Leaseb711d572012-10-02 13:14:11 -07002418 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08002419 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07002420 }
Victoria Lease37425c32012-10-16 16:08:48 -07002421 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08002422 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07002423 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002424 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002425 return null;
2426 } finally {
2427 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002428 }
2429 }
2430
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002431 /**
2432 * Provides an interface to inject and set the last location if location is not available
2433 * currently.
2434 *
2435 * This helps in cases where the product (Cars for example) has saved the last known location
2436 * before powering off. This interface lets the client inject the saved location while the GPS
2437 * chipset is getting its first fix, there by improving user experience.
2438 *
2439 * @param location - Location object to inject
2440 * @return true if update was successful, false if not
2441 */
2442 @Override
2443 public boolean injectLocation(Location location) {
2444 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
2445 "Location Hardware permission not granted to inject location");
2446 mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
2447 "Access Fine Location permission not granted to inject Location");
2448
2449 if (location == null) {
2450 if (D) {
2451 Log.d(TAG, "injectLocation(): called with null location");
2452 }
2453 return false;
2454 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002455 LocationProvider p = null;
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002456 String provider = location.getProvider();
2457 if (provider != null) {
2458 p = mProvidersByName.get(provider);
2459 }
2460 if (p == null) {
2461 if (D) {
2462 Log.d(TAG, "injectLocation(): unknown provider");
2463 }
2464 return false;
2465 }
2466 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002467 if (!isAllowedByUserSettingsLockedForUser(provider, mCurrentUserId)) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002468 if (D) {
2469 Log.d(TAG, "Location disabled in Settings for current user:" + mCurrentUserId);
2470 }
2471 return false;
2472 } else {
2473 // NOTE: If last location is already available, location is not injected. If
2474 // provider's normal source (like a GPS chipset) have already provided an output,
2475 // there is no need to inject this location.
2476 if (mLastLocation.get(provider) == null) {
2477 updateLastLocationLocked(location, provider);
2478 } else {
2479 if (D) {
2480 Log.d(TAG, "injectLocation(): Location exists. Not updating");
2481 }
2482 return false;
2483 }
2484 }
2485 }
2486 return true;
2487 }
2488
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002489 @Override
2490 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
2491 String packageName) {
2492 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002493 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2494 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002495 checkPendingIntent(intent);
2496 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002497 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2498 request.getProvider());
gomo48f1a642017-11-10 20:35:46 -08002499 // Require that caller can manage given document
2500 boolean callerHasLocationHardwarePermission =
2501 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
Maggieaa080f92018-01-04 15:35:11 -08002502 == PERMISSION_GRANTED;
gomo48f1a642017-11-10 20:35:46 -08002503 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
2504 callerHasLocationHardwarePermission);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002505
Victoria Lease37425c32012-10-16 16:08:48 -07002506 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002507
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002508 // geo-fence manager uses the public location API, need to clear identity
2509 int uid = Binder.getCallingUid();
Xiaohui Chena4490622015-09-22 15:29:31 -07002510 // TODO: http://b/23822629
2511 if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
Victoria Lease56e675b2012-11-05 19:25:06 -08002512 // temporary measure until geofences work for secondary users
2513 Log.w(TAG, "proximity alerts are currently available only to the primary user");
2514 return;
2515 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002516 long identity = Binder.clearCallingIdentity();
2517 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002518 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
2519 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002520 } finally {
2521 Binder.restoreCallingIdentity(identity);
2522 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002523 }
2524
2525 @Override
2526 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002527 checkPendingIntent(intent);
2528 checkPackageName(packageName);
2529
2530 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
2531
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002532 // geo-fence manager uses the public location API, need to clear identity
2533 long identity = Binder.clearCallingIdentity();
2534 try {
2535 mGeofenceManager.removeFence(geofence, intent);
2536 } finally {
2537 Binder.restoreCallingIdentity(identity);
2538 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002539 }
2540
2541
2542 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002543 public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002544 if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09002545 return false;
2546 }
2547
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002548 try {
Lifu Tang30f95a72016-01-07 23:20:38 -08002549 mGnssStatusProvider.registerGnssStatusCallback(callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002550 } catch (RemoteException e) {
Lifu Tang30f95a72016-01-07 23:20:38 -08002551 Slog.e(TAG, "mGpsStatusProvider.registerGnssStatusCallback failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002552 return false;
2553 }
2554 return true;
2555 }
2556
Nick Pellye0fd6932012-07-11 10:26:13 -07002557 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002558 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002559 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002560 try {
Lifu Tang30f95a72016-01-07 23:20:38 -08002561 mGnssStatusProvider.unregisterGnssStatusCallback(callback);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002562 } catch (Exception e) {
Lifu Tang30f95a72016-01-07 23:20:38 -08002563 Slog.e(TAG, "mGpsStatusProvider.unregisterGnssStatusCallback failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002564 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002565 }
2566 }
2567
Nick Pellye0fd6932012-07-11 10:26:13 -07002568 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002569 public boolean addGnssMeasurementsListener(
gomo48f1a642017-11-10 20:35:46 -08002570 IGnssMeasurementsListener listener, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002571 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07002572 return false;
2573 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002574
2575 synchronized (mLock) {
2576 Identity callerIdentity
2577 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Wyatt Riley11cc7492018-01-17 08:48:27 -08002578 mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002579 long identity = Binder.clearCallingIdentity();
2580 try {
2581 if (isThrottlingExemptLocked(callerIdentity)
2582 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002583 mActivityManager.getPackageImportance(packageName))) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002584 return mGnssMeasurementsProvider.addListener(listener);
2585 }
2586 } finally {
2587 Binder.restoreCallingIdentity(identity);
2588 }
2589
2590 return true;
2591 }
destradaaea8a8a62014-06-23 18:19:03 -07002592 }
2593
2594 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002595 public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002596 if (mGnssMeasurementsProvider == null) {
2597 return;
2598 }
2599
2600 synchronized (mLock) {
2601 mGnssMeasurementsListeners.remove(listener.asBinder());
2602 mGnssMeasurementsProvider.removeListener(listener);
Wei Liu5241a4c2015-05-11 14:00:36 -07002603 }
destradaaea8a8a62014-06-23 18:19:03 -07002604 }
2605
2606 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002607 public boolean addGnssNavigationMessageListener(
2608 IGnssNavigationMessageListener listener,
destradaa4b3e3932014-07-21 18:01:47 -07002609 String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002610 if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07002611 return false;
2612 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002613
2614 synchronized (mLock) {
2615 Identity callerIdentity
gomo48f1a642017-11-10 20:35:46 -08002616 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Wyatt Riley11cc7492018-01-17 08:48:27 -08002617 mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002618 long identity = Binder.clearCallingIdentity();
2619 try {
2620 if (isThrottlingExemptLocked(callerIdentity)
2621 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002622 mActivityManager.getPackageImportance(packageName))) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002623 return mGnssNavigationMessageProvider.addListener(listener);
2624 }
2625 } finally {
2626 Binder.restoreCallingIdentity(identity);
2627 }
2628
2629 return true;
2630 }
destradaa4b3e3932014-07-21 18:01:47 -07002631 }
2632
2633 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002634 public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
2635 if (mGnssNavigationMessageProvider != null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002636 synchronized (mLock) {
Wyatt Riley11cc7492018-01-17 08:48:27 -08002637 mGnssNavigationMessageListeners.remove(listener.asBinder());
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002638 mGnssNavigationMessageProvider.removeListener(listener);
2639 }
Wei Liu5241a4c2015-05-11 14:00:36 -07002640 }
destradaa4b3e3932014-07-21 18:01:47 -07002641 }
2642
2643 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002644 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002645 if (provider == null) {
2646 // throw NullPointerException to remain compatible with previous implementation
2647 throw new NullPointerException();
2648 }
Victoria Lease37425c32012-10-16 16:08:48 -07002649 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2650 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002651
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002652 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04002653 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
Maggieaa080f92018-01-04 15:35:11 -08002654 != PERMISSION_GRANTED)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002655 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2656 }
2657
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002658 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002659 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002660 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07002661
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002662 p.sendExtraCommand(command, extras);
2663 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002664 }
2665 }
2666
Nick Pellye0fd6932012-07-11 10:26:13 -07002667 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002668 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07002669 if (Binder.getCallingUid() != Process.myUid()) {
2670 throw new SecurityException(
2671 "calling sendNiResponse from outside of the system is not allowed");
2672 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04002673 try {
2674 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002675 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002676 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04002677 return false;
2678 }
2679 }
2680
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002681 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002682 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11002683 * @throws SecurityException if the provider is not allowed to be
gomo48f1a642017-11-10 20:35:46 -08002684 * accessed by the caller
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002685 */
Nick Pellye0fd6932012-07-11 10:26:13 -07002686 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002687 public ProviderProperties getProviderProperties(String provider) {
Victoria Lease37425c32012-10-16 16:08:48 -07002688 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2689 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002690
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002691 LocationProvider p;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002692 synchronized (mLock) {
2693 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002694 }
2695
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002696 if (p == null) return null;
2697 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002698 }
2699
Jason Monkb71218a2015-06-17 14:44:39 -04002700 /**
2701 * @return null if the provider does not exist
2702 * @throws SecurityException if the provider is not allowed to be
gomo48f1a642017-11-10 20:35:46 -08002703 * accessed by the caller
Jason Monkb71218a2015-06-17 14:44:39 -04002704 */
2705 @Override
2706 public String getNetworkProviderPackage() {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002707 LocationProvider p;
Jason Monkb71218a2015-06-17 14:44:39 -04002708 synchronized (mLock) {
Jason Monkb71218a2015-06-17 14:44:39 -04002709 p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
2710 }
2711
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002712 if (p == null) {
2713 return null;
2714 }
2715 if (p.mProvider instanceof LocationProviderProxy) {
2716 return ((LocationProviderProxy) p.mProvider).getConnectedPackageName();
Jason Monkb71218a2015-06-17 14:44:39 -04002717 }
2718 return null;
2719 }
2720
Maggieaa080f92018-01-04 15:35:11 -08002721 /**
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002722 * Returns the current location enabled/disabled status for a user
Maggie2a9409e2018-03-21 11:47:28 -07002723 *
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002724 * @param userId the id of the user
2725 * @return true if location is enabled
Maggie2a9409e2018-03-21 11:47:28 -07002726 */
2727 @Override
2728 public boolean isLocationEnabledForUser(int userId) {
2729 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2730 checkInteractAcrossUsersPermission(userId);
2731
2732 long identity = Binder.clearCallingIdentity();
2733 try {
2734 synchronized (mLock) {
2735 final String allowedProviders = Settings.Secure.getStringForUser(
2736 mContext.getContentResolver(),
2737 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
2738 userId);
2739 if (allowedProviders == null) {
2740 return false;
2741 }
2742 final List<String> providerList = Arrays.asList(allowedProviders.split(","));
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002743 for (String provider : mRealProviders.keySet()) {
Maggie2a9409e2018-03-21 11:47:28 -07002744 if (provider.equals(LocationManager.PASSIVE_PROVIDER)
2745 || provider.equals(LocationManager.FUSED_PROVIDER)) {
2746 continue;
2747 }
2748 if (providerList.contains(provider)) {
2749 return true;
2750 }
2751 }
2752 return false;
2753 }
2754 } finally {
2755 Binder.restoreCallingIdentity(identity);
2756 }
2757 }
2758
2759 /**
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002760 * Enable or disable location for a user
Maggie2a9409e2018-03-21 11:47:28 -07002761 *
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002762 * @param enabled true to enable location, false to disable location
2763 * @param userId the id of the user
Maggie2a9409e2018-03-21 11:47:28 -07002764 */
2765 @Override
2766 public void setLocationEnabledForUser(boolean enabled, int userId) {
2767 mContext.enforceCallingPermission(
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002768 android.Manifest.permission.WRITE_SECURE_SETTINGS,
2769 "Requires WRITE_SECURE_SETTINGS permission");
Maggie2a9409e2018-03-21 11:47:28 -07002770
2771 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2772 checkInteractAcrossUsersPermission(userId);
2773
2774 long identity = Binder.clearCallingIdentity();
2775 try {
2776 synchronized (mLock) {
2777 final Set<String> allRealProviders = mRealProviders.keySet();
2778 // Update all providers on device plus gps and network provider when disabling
2779 // location
2780 Set<String> allProvidersSet = new ArraySet<>(allRealProviders.size() + 2);
2781 allProvidersSet.addAll(allRealProviders);
2782 // When disabling location, disable gps and network provider that could have been
2783 // enabled by location mode api.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002784 if (!enabled) {
Maggie2a9409e2018-03-21 11:47:28 -07002785 allProvidersSet.add(LocationManager.GPS_PROVIDER);
2786 allProvidersSet.add(LocationManager.NETWORK_PROVIDER);
2787 }
2788 if (allProvidersSet.isEmpty()) {
2789 return;
2790 }
2791 // to ensure thread safety, we write the provider name with a '+' or '-'
2792 // and let the SettingsProvider handle it rather than reading and modifying
2793 // the list of enabled providers.
2794 final String prefix = enabled ? "+" : "-";
2795 StringBuilder locationProvidersAllowed = new StringBuilder();
2796 for (String provider : allProvidersSet) {
2797 if (provider.equals(LocationManager.PASSIVE_PROVIDER)
2798 || provider.equals(LocationManager.FUSED_PROVIDER)) {
2799 continue;
2800 }
2801 locationProvidersAllowed.append(prefix);
2802 locationProvidersAllowed.append(provider);
2803 locationProvidersAllowed.append(",");
2804 }
2805 // Remove the trailing comma
2806 locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
2807 Settings.Secure.putStringForUser(
2808 mContext.getContentResolver(),
2809 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
2810 locationProvidersAllowed.toString(),
2811 userId);
2812 }
2813 } finally {
2814 Binder.restoreCallingIdentity(identity);
2815 }
2816 }
2817
2818 /**
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002819 * Returns the current enabled/disabled status of a location provider and user
Maggie2a9409e2018-03-21 11:47:28 -07002820 *
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002821 * @param providerName name of the provider
2822 * @param userId the id of the user
2823 * @return true if the provider exists and is enabled
Maggie2a9409e2018-03-21 11:47:28 -07002824 */
2825 @Override
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002826 public boolean isProviderEnabledForUser(String providerName, int userId) {
Maggie2a9409e2018-03-21 11:47:28 -07002827 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2828 checkInteractAcrossUsersPermission(userId);
2829
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002830 if (!isLocationEnabledForUser(userId)) {
2831 return false;
2832 }
2833
Maggie2a9409e2018-03-21 11:47:28 -07002834 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2835 // so we discourage its use
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002836 if (LocationManager.FUSED_PROVIDER.equals(providerName)) return false;
Maggie2a9409e2018-03-21 11:47:28 -07002837
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002838 long identity = Binder.clearCallingIdentity();
2839 try {
2840 LocationProvider provider;
2841 synchronized (mLock) {
2842 provider = mProvidersByName.get(providerName);
2843 }
2844 return provider != null && provider.isEnabled();
2845 } finally {
2846 Binder.restoreCallingIdentity(identity);
Maggie2a9409e2018-03-21 11:47:28 -07002847 }
2848 }
2849
2850 /**
2851 * Enable or disable a single location provider.
2852 *
2853 * @param provider name of the provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002854 * @param enabled true to enable the provider. False to disable the provider
2855 * @param userId the id of the user to set
Maggie2a9409e2018-03-21 11:47:28 -07002856 * @return true if the value was set, false on errors
2857 */
2858 @Override
2859 public boolean setProviderEnabledForUser(String provider, boolean enabled, int userId) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002860 return false;
Maggieaa080f92018-01-04 15:35:11 -08002861 }
2862
2863 /**
Maggie2a9409e2018-03-21 11:47:28 -07002864 * Method for checking INTERACT_ACROSS_USERS permission if specified user id is not the same as
2865 * current user id
2866 *
2867 * @param userId the user id to get or set value
2868 */
2869 private void checkInteractAcrossUsersPermission(int userId) {
2870 int uid = Binder.getCallingUid();
2871 if (UserHandle.getUserId(uid) != userId) {
2872 if (ActivityManager.checkComponentPermission(
2873 android.Manifest.permission.INTERACT_ACROSS_USERS, uid, -1, true)
2874 != PERMISSION_GRANTED) {
2875 throw new SecurityException("Requires INTERACT_ACROSS_USERS permission");
2876 }
2877 }
2878 }
2879
2880 /**
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002881 * Returns "true" if the UID belongs to a bound location provider.
2882 *
2883 * @param uid the uid
2884 * @return true if uid belongs to a bound location provider
2885 */
2886 private boolean isUidALocationProvider(int uid) {
2887 if (uid == Process.SYSTEM_UID) {
2888 return true;
2889 }
2890 if (mGeocodeProvider != null) {
David Christie1f141c12014-05-14 15:11:15 -07002891 if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002892 }
2893 for (LocationProviderProxy proxy : mProxyProviders) {
David Christie1f141c12014-05-14 15:11:15 -07002894 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002895 }
2896 return false;
2897 }
2898
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002899 private void checkCallerIsProvider() {
2900 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
Maggieaa080f92018-01-04 15:35:11 -08002901 == PERMISSION_GRANTED) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002902 return;
2903 }
2904
2905 // Previously we only used the INSTALL_LOCATION_PROVIDER
2906 // check. But that is system or signature
2907 // protection level which is not flexible enough for
2908 // providers installed oustide the system image. So
2909 // also allow providers with a UID matching the
2910 // currently bound package name
2911
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002912 if (isUidALocationProvider(Binder.getCallingUid())) {
2913 return;
2914 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002915
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002916 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2917 "or UID of a currently bound location provider");
2918 }
2919
David Christie1f141c12014-05-14 15:11:15 -07002920 /**
2921 * Returns true if the given package belongs to the given uid.
2922 */
2923 private boolean doesUidHavePackage(int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002924 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002925 return false;
2926 }
David Christie1f141c12014-05-14 15:11:15 -07002927 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2928 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002929 return false;
2930 }
David Christie1f141c12014-05-14 15:11:15 -07002931 for (String name : packageNames) {
2932 if (packageName.equals(name)) {
2933 return true;
2934 }
2935 }
2936 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002937 }
2938
Nick Pellye0fd6932012-07-11 10:26:13 -07002939 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05002940 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002941 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04002942
Nick Pelly2eeeec22012-07-18 13:13:37 -07002943 if (!location.isComplete()) {
2944 Log.w(TAG, "Dropping incomplete location: " + location);
2945 return;
2946 }
2947
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002948 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2949 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05002950 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002951 mLocationHandler.sendMessageAtFrontOfQueue(m);
2952 }
2953
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002954
Laurent Tu75defb62012-11-01 16:21:52 -07002955 private static boolean shouldBroadcastSafe(
2956 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002957 // Always broadcast the first update
2958 if (lastLoc == null) {
2959 return true;
2960 }
2961
Nick Pellyf1be6862012-05-15 10:53:42 -07002962 // Check whether sufficient time has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002963 long minTime = record.mRealRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002964 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2965 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002966 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002967 return false;
2968 }
2969
2970 // Check whether sufficient distance has been traveled
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002971 double minDistance = record.mRealRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002972 if (minDistance > 0.0) {
2973 if (loc.distanceTo(lastLoc) <= minDistance) {
2974 return false;
2975 }
2976 }
2977
Laurent Tu75defb62012-11-01 16:21:52 -07002978 // Check whether sufficient number of udpates is left
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002979 if (record.mRealRequest.getNumUpdates() <= 0) {
Laurent Tu75defb62012-11-01 16:21:52 -07002980 return false;
2981 }
2982
2983 // Check whether the expiry date has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002984 return record.mRealRequest.getExpireAt() >= now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002985 }
2986
Mike Lockwooda4903f22010-02-17 06:42:23 -05002987 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002988 if (D) Log.d(TAG, "incoming location: " + location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002989 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05002990 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
Laurent Tu60ec50a2012-10-04 17:00:10 -07002991 // Skip if the provider is unknown.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002992 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002993 if (p == null) return;
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002994 updateLastLocationLocked(location, provider);
2995 // mLastLocation should have been updated from the updateLastLocationLocked call above.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002996 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002997 if (lastLocation == null) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002998 Log.e(TAG, "handleLocationChangedLocked() updateLastLocation failed");
2999 return;
Mike Lockwood4e50b782009-04-03 08:24:43 -07003000 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003001
David Christie1b9b7b12013-04-15 15:31:11 -07003002 // Update last known coarse interval location if enough time has passed.
3003 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
3004 if (lastLocationCoarseInterval == null) {
3005 lastLocationCoarseInterval = new Location(location);
3006 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
3007 }
3008 long timeDiffNanos = location.getElapsedRealtimeNanos()
3009 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
3010 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
3011 lastLocationCoarseInterval.set(location);
3012 }
3013 // Don't ever return a coarse location that is more recent than the allowed update
3014 // interval (i.e. don't allow an app to keep registering and unregistering for
3015 // location updates to overcome the minimum interval).
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003016 Location noGPSLocation =
David Christie1b9b7b12013-04-15 15:31:11 -07003017 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3018
Laurent Tu60ec50a2012-10-04 17:00:10 -07003019 // Skip if there are no UpdateRecords for this provider.
3020 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
3021 if (records == null || records.size() == 0) return;
3022
Victoria Lease09016ab2012-09-16 12:33:15 -07003023 // Fetch coarse location
3024 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07003025 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003026 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
3027 }
3028
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003029 // Fetch latest status update time
3030 long newStatusUpdateTime = p.getStatusUpdateTime();
3031
David Christie2ff96af2014-01-30 16:09:37 -08003032 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003033 Bundle extras = new Bundle();
3034 int status = p.getStatus(extras);
3035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003036 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003037 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07003038
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003039 // Broadcast location to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003040 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003041 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07003042 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07003043
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003044 int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
3045 if (!isCurrentProfile(receiverUserId)
3046 && !isUidALocationProvider(receiver.mIdentity.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07003047 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07003048 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07003049 " (current user: " + mCurrentUserId + ", app: " +
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003050 receiver.mIdentity.mPackageName + ")");
Victoria Leaseb711d572012-10-02 13:14:11 -07003051 }
3052 continue;
3053 }
3054
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003055 if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
gomo48f1a642017-11-10 20:35:46 -08003056 if (D) {
3057 Log.d(TAG, "skipping loc update for blacklisted app: " +
3058 receiver.mIdentity.mPackageName);
3059 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07003060 continue;
3061 }
3062
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003063 if (!reportLocationAccessNoThrow(
3064 receiver.mIdentity.mPid,
3065 receiver.mIdentity.mUid,
3066 receiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003067 receiver.mAllowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08003068 if (D) {
3069 Log.d(TAG, "skipping loc update for no op app: " +
3070 receiver.mIdentity.mPackageName);
3071 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003072 continue;
3073 }
3074
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003075 Location notifyLocation;
Victoria Lease37425c32012-10-16 16:08:48 -07003076 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
3077 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003078 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07003079 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003080 }
Victoria Lease09016ab2012-09-16 12:33:15 -07003081 if (notifyLocation != null) {
3082 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07003083 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003084 if (lastLoc == null) {
3085 lastLoc = new Location(notifyLocation);
3086 r.mLastFixBroadcast = lastLoc;
3087 } else {
3088 lastLoc.set(notifyLocation);
3089 }
3090 if (!receiver.callLocationChangedLocked(notifyLocation)) {
3091 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
3092 receiverDead = true;
3093 }
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003094 r.mRealRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003095 }
3096 }
3097
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003098 // TODO: location provider status callbacks have been disabled and deprecated, and are
3099 // guarded behind this setting now. should be removed completely post-Q
3100 if (Settings.Global.getInt(mContext.getContentResolver(),
3101 LOCATION_DISABLE_STATUS_CALLBACKS, 1) == 0) {
3102 long prevStatusUpdateTime = r.mLastStatusBroadcast;
3103 if ((newStatusUpdateTime > prevStatusUpdateTime)
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003104 && (prevStatusUpdateTime != 0 || status != AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003105
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003106 r.mLastStatusBroadcast = newStatusUpdateTime;
3107 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
3108 receiverDead = true;
3109 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
3110 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07003111 }
3112 }
3113
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003114 // track expired records
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003115 if (r.mRealRequest.getNumUpdates() <= 0 || r.mRealRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003116 if (deadUpdateRecords == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003117 deadUpdateRecords = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003118 }
3119 deadUpdateRecords.add(r);
3120 }
3121 // track dead receivers
3122 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07003123 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003124 deadReceivers = new ArrayList<>();
Mike Lockwood03ca2162010-04-01 08:10:09 -07003125 }
3126 if (!deadReceivers.contains(receiver)) {
3127 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003128 }
3129 }
3130 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003131
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003132 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003133 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003134 for (Receiver receiver : deadReceivers) {
3135 removeUpdatesLocked(receiver);
3136 }
3137 }
3138 if (deadUpdateRecords != null) {
3139 for (UpdateRecord r : deadUpdateRecords) {
3140 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003141 }
Victoria Lease8b38b292012-12-04 15:04:43 -08003142 applyRequirementsLocked(provider);
3143 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003144 }
3145
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003146 /**
3147 * Updates last location with the given location
3148 *
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003149 * @param location new location to update
3150 * @param provider Location provider to update for
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003151 */
3152 private void updateLastLocationLocked(Location location, String provider) {
3153 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3154 Location lastNoGPSLocation;
3155 Location lastLocation = mLastLocation.get(provider);
3156 if (lastLocation == null) {
3157 lastLocation = new Location(provider);
3158 mLastLocation.put(provider, lastLocation);
3159 } else {
3160 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3161 if (noGPSLocation == null && lastNoGPSLocation != null) {
3162 // New location has no no-GPS location: adopt last no-GPS location. This is set
3163 // directly into location because we do not want to notify COARSE clients.
3164 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
3165 }
3166 }
3167 lastLocation.set(location);
3168 }
3169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003170 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08003171 public LocationWorkerHandler(Looper looper) {
3172 super(looper, null, true);
3173 }
3174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003175 @Override
3176 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003177 switch (msg.what) {
3178 case MSG_LOCATION_CHANGED:
3179 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
3180 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003181 }
3182 }
3183 }
3184
Victoria Lease54ca7ae2013-01-08 09:39:50 -08003185 private boolean isMockProvider(String provider) {
3186 synchronized (mLock) {
3187 return mMockProviders.containsKey(provider);
3188 }
3189 }
3190
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003191 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08003192 // create a working copy of the incoming Location so that the service can modify it without
3193 // disturbing the caller's copy
3194 Location myLocation = new Location(location);
3195 String provider = myLocation.getProvider();
3196
3197 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
3198 // bit if location did not come from a mock provider because passive/fused providers can
3199 // forward locations from mock providers, and should not grant them legitimacy in doing so.
3200 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
3201 myLocation.setIsFromMockProvider(true);
3202 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08003203
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003204 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003205 if (!passive) {
3206 // notify passive provider of the new location
3207 mPassiveProvider.updateLocation(myLocation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003208 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003209 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003210 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003211 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003212
Mike Lockwoode97ae402010-09-29 15:23:46 -04003213 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
3214 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003215 public void onPackageDisappeared(String packageName, int reason) {
3216 // remove all receivers associated with this package name
3217 synchronized (mLock) {
3218 ArrayList<Receiver> deadReceivers = null;
3219
3220 for (Receiver receiver : mReceivers.values()) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003221 if (receiver.mIdentity.mPackageName.equals(packageName)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003222 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003223 deadReceivers = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003224 }
3225 deadReceivers.add(receiver);
3226 }
3227 }
3228
3229 // perform removal outside of mReceivers loop
3230 if (deadReceivers != null) {
3231 for (Receiver receiver : deadReceivers) {
3232 removeUpdatesLocked(receiver);
3233 }
3234 }
3235 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003236 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04003237 };
3238
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003239 // Geocoder
3240
Nick Pellye0fd6932012-07-11 10:26:13 -07003241 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04003242 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07003243 return mGeocodeProvider != null;
3244 }
3245
Nick Pellye0fd6932012-07-11 10:26:13 -07003246 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003247 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003248 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003249 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003250 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
3251 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003252 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003253 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003254 }
3255
Mike Lockwooda55c3212009-04-15 11:10:11 -04003256
Nick Pellye0fd6932012-07-11 10:26:13 -07003257 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003258 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04003259 double lowerLeftLatitude, double lowerLeftLongitude,
3260 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003261 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003262
3263 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003264 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
3265 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
3266 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003267 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003268 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003269 }
3270
3271 // Mock Providers
3272
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003273 private boolean canCallerAccessMockLocation(String opPackageName) {
3274 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
3275 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003276 }
3277
Nick Pellye0fd6932012-07-11 10:26:13 -07003278 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003279 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
3280 if (!canCallerAccessMockLocation(opPackageName)) {
3281 return;
3282 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003283
Mike Lockwooda4903f22010-02-17 06:42:23 -05003284 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
3285 throw new IllegalArgumentException("Cannot mock the passive location provider");
3286 }
3287
Mike Lockwood86328a92009-10-23 08:38:25 -04003288 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003289 synchronized (mLock) {
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003290 // remove the real provider if we are replacing GPS or network provider
3291 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07003292 || LocationManager.NETWORK_PROVIDER.equals(name)
3293 || LocationManager.FUSED_PROVIDER.equals(name)) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003294 LocationProvider p = mProvidersByName.get(name);
Mike Lockwoodd03ff942010-02-09 08:46:14 -05003295 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003296 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003297 }
3298 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003299 addTestProviderLocked(name, properties);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003300 }
Mike Lockwood86328a92009-10-23 08:38:25 -04003301 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003302 }
3303
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003304 private void addTestProviderLocked(String name, ProviderProperties properties) {
3305 if (mProvidersByName.get(name) != null) {
3306 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
3307 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003308
3309 LocationProvider provider = new LocationProvider(name);
3310 MockProvider mockProvider = new MockProvider(provider, properties);
3311
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003312 addProviderLocked(provider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003313 mMockProviders.put(name, mockProvider);
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003314 mLastLocation.put(name, null);
3315 mLastLocationCoarseInterval.put(name, null);
3316 }
3317
Nick Pellye0fd6932012-07-11 10:26:13 -07003318 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003319 public void removeTestProvider(String provider, String opPackageName) {
3320 if (!canCallerAccessMockLocation(opPackageName)) {
3321 return;
3322 }
3323
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003324 synchronized (mLock) {
You Kima6d0b6f2012-10-28 03:58:44 +09003325 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003326 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003327 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3328 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003329
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003330 long identity = Binder.clearCallingIdentity();
3331 try {
3332 removeProviderLocked(mProvidersByName.get(provider));
3333
3334 // reinstate real provider if available
3335 LocationProvider realProvider = mRealProviders.get(provider);
3336 if (realProvider != null) {
3337 addProviderLocked(realProvider);
3338 }
3339 mLastLocation.put(provider, null);
3340 mLastLocationCoarseInterval.put(provider, null);
3341 } finally {
3342 Binder.restoreCallingIdentity(identity);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003343 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003344 }
3345 }
3346
Nick Pellye0fd6932012-07-11 10:26:13 -07003347 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003348 public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
3349 if (!canCallerAccessMockLocation(opPackageName)) {
3350 return;
3351 }
3352
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003353 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003354 MockProvider mockProvider = mMockProviders.get(provider);
3355 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003356 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3357 }
Tom O'Neilla206a0f2016-12-15 10:26:28 -08003358
3359 // Ensure that the location is marked as being mock. There's some logic to do this in
3360 // handleLocationChanged(), but it fails if loc has the wrong provider (bug 33091107).
3361 Location mock = new Location(loc);
3362 mock.setIsFromMockProvider(true);
3363
3364 if (!TextUtils.isEmpty(loc.getProvider()) && !provider.equals(loc.getProvider())) {
3365 // The location has an explicit provider that is different from the mock provider
3366 // name. The caller may be trying to fool us via bug 33091107.
3367 EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
3368 provider + "!=" + loc.getProvider());
3369 }
3370
Mike Lockwood95427cd2009-05-07 13:27:54 -04003371 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
3372 long identity = Binder.clearCallingIdentity();
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003373 try {
3374 mockProvider.setLocation(mock);
3375 } finally {
3376 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003377 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003378 }
3379 }
3380
Nick Pellye0fd6932012-07-11 10:26:13 -07003381 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003382 public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
3383 if (!canCallerAccessMockLocation(opPackageName)) {
3384 return;
3385 }
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003386
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003387 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003388 MockProvider mockProvider = mMockProviders.get(provider);
3389 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003390 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3391 }
Mike Lockwood86328a92009-10-23 08:38:25 -04003392 long identity = Binder.clearCallingIdentity();
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003393 try {
3394 mockProvider.setEnabled(enabled);
3395 } finally {
3396 Binder.restoreCallingIdentity(identity);
3397 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003398 }
3399 }
3400
Nick Pellye0fd6932012-07-11 10:26:13 -07003401 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003402 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
3403 String opPackageName) {
3404 if (!canCallerAccessMockLocation(opPackageName)) {
3405 return;
3406 }
3407
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003408 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003409 MockProvider mockProvider = mMockProviders.get(provider);
3410 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003411 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3412 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003413 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003414 }
3415 }
3416
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003417 private void log(String log) {
3418 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003419 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003420 }
3421 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003422
3423 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003424 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06003425 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Nick Pellye0fd6932012-07-11 10:26:13 -07003426
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003427 synchronized (mLock) {
Siddharth Raybb608c82017-03-16 11:33:34 -07003428 if (args.length > 0 && args[0].equals("--gnssmetrics")) {
3429 if (mGnssMetricsProvider != null) {
3430 pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
3431 }
3432 return;
3433 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003434 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003435 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003436 for (Receiver receiver : mReceivers.values()) {
3437 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003438 }
David Christie2ff96af2014-01-30 16:09:37 -08003439 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003440 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
3441 pw.println(" " + entry.getKey() + ":");
3442 for (UpdateRecord record : entry.getValue()) {
3443 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003444 }
3445 }
Wyatt Riley11cc7492018-01-17 08:48:27 -08003446 pw.println(" Active GnssMeasurement Listeners:");
3447 for (Identity identity : mGnssMeasurementsListeners.values()) {
3448 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3449 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3450 }
3451 pw.println(" Active GnssNavigationMessage Listeners:");
3452 for (Identity identity : mGnssNavigationMessageListeners.values()) {
3453 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3454 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3455 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003456 pw.println(" Overlay Provider Packages:");
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003457 for (LocationProvider provider : mProviders) {
3458 if (provider.mProvider instanceof LocationProviderProxy) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003459 pw.println(" " + provider.getName() + ": "
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003460 + ((LocationProviderProxy) provider.mProvider)
3461 .getConnectedPackageName());
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003462 }
3463 }
David Christie2ff96af2014-01-30 16:09:37 -08003464 pw.println(" Historical Records by Provider:");
3465 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
3466 : mRequestStatistics.statistics.entrySet()) {
3467 PackageProviderKey key = entry.getKey();
3468 PackageStatistics stats = entry.getValue();
3469 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
3470 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003471 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003472 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
3473 String provider = entry.getKey();
3474 Location location = entry.getValue();
3475 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003476 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003477
David Christie1b9b7b12013-04-15 15:31:11 -07003478 pw.println(" Last Known Locations Coarse Intervals:");
3479 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
3480 String provider = entry.getKey();
3481 Location location = entry.getValue();
3482 pw.println(" " + provider + ": " + location);
3483 }
3484
Nick Pellye0fd6932012-07-11 10:26:13 -07003485 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003486
Nick Pelly4035f5a2012-08-17 14:43:49 -07003487 pw.append(" ");
3488 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003489 if (mMockProviders.size() > 0) {
3490 pw.println(" Mock Providers:");
3491 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003492 i.getValue().dump(fd, pw, args);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003493 }
3494 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003495
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08003496 if (!mBackgroundThrottlePackageWhitelist.isEmpty()) {
3497 pw.println(" Throttling Whitelisted Packages:");
3498 for (String packageName : mBackgroundThrottlePackageWhitelist) {
3499 pw.println(" " + packageName);
3500 }
3501 }
3502
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003503 pw.append(" fudger: ");
gomo48f1a642017-11-10 20:35:46 -08003504 mLocationFudger.dump(fd, pw, args);
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003505
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003506 if (args.length > 0 && "short".equals(args[0])) {
3507 return;
3508 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003509 for (LocationProvider provider : mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003510 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003511 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08003512 if (mGnssBatchingInProgress) {
3513 pw.println(" GNSS batching in progress");
3514 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003515 }
3516 }
3517}