blob: c5ab932cae0254016824391665e1878a352237f3 [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;
20
Wyatt Rileycf879db2017-01-12 13:57:38 -080021import android.annotation.NonNull;
Wyatt Riley49097c02018-03-15 09:14:43 -070022import android.annotation.Nullable;
Maggieaa080f92018-01-04 15:35:11 -080023import android.app.ActivityManager;
24import android.app.AppOpsManager;
25import android.app.PendingIntent;
26import android.content.BroadcastReceiver;
27import android.content.ContentResolver;
28import android.content.Context;
29import android.content.Intent;
30import android.content.IntentFilter;
31import android.content.pm.ApplicationInfo;
32import android.content.pm.PackageInfo;
33import android.content.pm.PackageManager;
34import android.content.pm.PackageManager.NameNotFoundException;
35import android.content.pm.PackageManagerInternal;
36import android.content.pm.ResolveInfo;
37import android.content.pm.Signature;
38import android.content.res.Resources;
39import android.database.ContentObserver;
40import android.hardware.location.ActivityRecognitionHardware;
41import android.location.Address;
42import android.location.Criteria;
43import android.location.GeocoderParams;
44import android.location.Geofence;
45import android.location.IBatchedLocationCallback;
46import android.location.IGnssMeasurementsListener;
47import android.location.IGnssNavigationMessageListener;
48import android.location.IGnssStatusListener;
49import android.location.IGnssStatusProvider;
50import android.location.IGpsGeofenceHardware;
51import android.location.ILocationListener;
52import android.location.ILocationManager;
53import android.location.INetInitiatedListener;
54import android.location.Location;
55import android.location.LocationManager;
56import android.location.LocationProvider;
57import android.location.LocationRequest;
58import android.os.Binder;
59import android.os.Bundle;
60import android.os.Handler;
61import android.os.IBinder;
62import android.os.Looper;
63import android.os.Message;
64import android.os.PowerManager;
65import android.os.Process;
66import android.os.RemoteException;
67import android.os.SystemClock;
68import android.os.UserHandle;
69import android.os.UserManager;
70import android.os.WorkSource;
Narayan Kamath32684dd2018-01-08 17:32:51 +000071import android.os.WorkSource.WorkChain;
Maggieaa080f92018-01-04 15:35:11 -080072import android.provider.Settings;
73import android.text.TextUtils;
Soonil Nagarkar681d7112017-02-23 17:14:16 -080074import android.util.ArrayMap;
Soonil Nagarkar2b565df2017-02-14 13:33:23 -080075import android.util.ArraySet;
Maggieaa080f92018-01-04 15:35:11 -080076import android.util.EventLog;
77import android.util.Log;
78import android.util.Slog;
destradaaea8a8a62014-06-23 18:19:03 -070079import com.android.internal.content.PackageMonitor;
80import com.android.internal.location.ProviderProperties;
81import com.android.internal.location.ProviderRequest;
82import com.android.internal.os.BackgroundThread;
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -070083import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060084import com.android.internal.util.DumpUtils;
destradaaa4fa3b52014-07-09 10:46:39 -070085import com.android.server.location.ActivityRecognitionProxy;
destradaaea8a8a62014-06-23 18:19:03 -070086import com.android.server.location.GeocoderProxy;
87import com.android.server.location.GeofenceManager;
88import com.android.server.location.GeofenceProxy;
Yu-Han Yang3557cc72018-03-21 12:48:36 -070089import com.android.server.location.GnssBatchingProvider;
Lifu Tang818aa2c2016-02-01 01:52:00 -080090import com.android.server.location.GnssLocationProvider;
91import com.android.server.location.GnssMeasurementsProvider;
92import com.android.server.location.GnssNavigationMessageProvider;
destradaaea8a8a62014-06-23 18:19:03 -070093import com.android.server.location.LocationBlacklist;
94import com.android.server.location.LocationFudger;
95import com.android.server.location.LocationProviderInterface;
96import com.android.server.location.LocationProviderProxy;
97import com.android.server.location.LocationRequestStatistics;
98import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
99import com.android.server.location.LocationRequestStatistics.PackageStatistics;
100import com.android.server.location.MockProvider;
101import com.android.server.location.PassiveProvider;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400102import java.io.FileDescriptor;
103import java.io.PrintWriter;
104import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700105import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400106import java.util.HashMap;
107import java.util.HashSet;
108import java.util.List;
109import java.util.Map;
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800110import java.util.Map.Entry;
Wyatt Rileycf879db2017-01-12 13:57:38 -0800111import java.util.NoSuchElementException;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400112import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113
114/**
115 * The service class that manages LocationProviders and issues location
116 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 */
Victoria Lease5cd731a2012-12-19 15:04:21 -0800118public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -0800120 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700121
Olivier Gaillard7a222662017-11-20 16:07:24 +0000122 private static final String WAKELOCK_KEY = "*location*";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123
Victoria Lease37425c32012-10-16 16:08:48 -0700124 // Location resolution level: no location data whatsoever
125 private static final int RESOLUTION_LEVEL_NONE = 0;
126 // Location resolution level: coarse location data only
127 private static final int RESOLUTION_LEVEL_COARSE = 1;
128 // Location resolution level: fine location data
129 private static final int RESOLUTION_LEVEL_FINE = 2;
130
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700132 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700134 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400135 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700136 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
137
138 private static final String NETWORK_LOCATION_SERVICE_ACTION =
Stan Chesnutt39062dd2013-07-22 14:33:30 -0700139 "com.android.location.service.v3.NetworkLocationProvider";
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700140 private static final String FUSED_LOCATION_SERVICE_ACTION =
141 "com.android.location.service.FusedLocationProvider";
142
143 private static final int MSG_LOCATION_CHANGED = 1;
144
David Christie1b9b7b12013-04-15 15:31:11 -0700145 private static final long NANOS_PER_MILLI = 1000000L;
146
David Christie0b837452013-07-29 16:02:13 -0700147 // The maximum interval a location request can have and still be considered "high power".
148 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
149
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700150 private static final int FOREGROUND_IMPORTANCE_CUTOFF
gomo48f1a642017-11-10 20:35:46 -0800151 = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700152
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800153 // default background throttling interval if not overriden in settings
Soonil Nagarkarde6780a2017-02-07 10:39:41 -0800154 private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800155
Nick Pellyf1be6862012-05-15 10:53:42 -0700156 // Location Providers may sometimes deliver location updates
157 // slightly faster that requested - provide grace period so
158 // we don't unnecessarily filter events that are otherwise on
159 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700160 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700161
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700162 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
163
164 private final Context mContext;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800165 private final AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700166
167 // used internally for synchronization
168 private final Object mLock = new Object();
169
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700170 // --- fields below are final after systemRunning() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700171 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700172 private GeofenceManager mGeofenceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700173 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700174 private PowerManager mPowerManager;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800175 private ActivityManager mActivityManager;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700176 private UserManager mUserManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700177 private GeocoderProxy mGeocodeProvider;
Lifu Tang30f95a72016-01-07 23:20:38 -0800178 private IGnssStatusProvider mGnssStatusProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700179 private INetInitiatedListener mNetInitiatedListener;
180 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700181 private PassiveProvider mPassiveProvider; // track passive provider for special cases
182 private LocationBlacklist mBlacklist;
Lifu Tang818aa2c2016-02-01 01:52:00 -0800183 private GnssMeasurementsProvider mGnssMeasurementsProvider;
184 private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
Wei Liu5241a4c2015-05-11 14:00:36 -0700185 private IGpsGeofenceHardware mGpsGeofenceProxy;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700186
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700187 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 // Set of providers that are explicitly enabled
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700189 // Only used by passive, fused & test. Network & GPS are controlled separately, and not listed.
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800190 private final Set<String> mEnabledProviders = new HashSet<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191
192 // Set of providers that are explicitly disabled
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800193 private final Set<String> mDisabledProviders = new HashSet<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700195 // Mock (test) providers
196 private final HashMap<String, MockProvider> mMockProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800197 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700199 // all receivers
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800200 private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700202 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500203 private final ArrayList<LocationProviderInterface> mProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800204 new ArrayList<>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400205
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700206 // real providers, saved here when mocked out
207 private final HashMap<String, LocationProviderInterface> mRealProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800208 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700210 // mapping from provider name to provider
211 private final HashMap<String, LocationProviderInterface> mProvidersByName =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800212 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700214 // mapping from provider name to all its UpdateRecords
215 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800216 new HashMap<>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700217
David Christie2ff96af2014-01-30 16:09:37 -0800218 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
219
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700220 // mapping from provider name to last known location
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800221 private final HashMap<String, Location> mLastLocation = new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222
David Christie1b9b7b12013-04-15 15:31:11 -0700223 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
224 // locations stored here are not fudged for coarse permissions.
225 private final HashMap<String, Location> mLastLocationCoarseInterval =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800226 new HashMap<>();
David Christie1b9b7b12013-04-15 15:31:11 -0700227
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800228 // all providers that operate over proxy, for authorizing incoming location and whitelisting
229 // throttling
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700230 private final ArrayList<LocationProviderProxy> mProxyProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800231 new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232
Soonil Nagarkar2b565df2017-02-14 13:33:23 -0800233 private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800234
Wyatt Riley11cc7492018-01-17 08:48:27 -0800235 private final ArrayMap<IBinder, Identity> mGnssMeasurementsListeners = new ArrayMap<>();
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800236
Wyatt Riley11cc7492018-01-17 08:48:27 -0800237 private final ArrayMap<IBinder, Identity>
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800238 mGnssNavigationMessageListeners = new ArrayMap<>();
239
Victoria Lease38389b62012-09-30 11:44:22 -0700240 // current active user on the device - other users are denied location data
Xiaohui Chena4490622015-09-22 15:29:31 -0700241 private int mCurrentUserId = UserHandle.USER_SYSTEM;
gomo48f1a642017-11-10 20:35:46 -0800242 private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
Victoria Lease38389b62012-09-30 11:44:22 -0700243
Lifu Tang9363b942016-02-16 18:07:00 -0800244 private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
Lifu Tang82f893d2016-01-21 18:15:33 -0800245
Siddharth Raybb608c82017-03-16 11:33:34 -0700246 private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
Wyatt Rileyaa420d52017-07-03 15:14:42 -0700247
Yu-Han Yang3557cc72018-03-21 12:48:36 -0700248 private GnssBatchingProvider mGnssBatchingProvider;
Wyatt Rileycf879db2017-01-12 13:57:38 -0800249 private IBatchedLocationCallback mGnssBatchingCallback;
250 private LinkedCallback mGnssBatchingDeathCallback;
251 private boolean mGnssBatchingInProgress = false;
252
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700253 public LocationManagerService(Context context) {
254 super();
255 mContext = context;
gomo48f1a642017-11-10 20:35:46 -0800256 mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800257
Svet Ganovadc1cf42015-06-15 16:36:24 -0700258 // Let the package manager query which are the default location
259 // providers as they get certain permissions granted by default.
260 PackageManagerInternal packageManagerInternal = LocalServices.getService(
261 PackageManagerInternal.class);
262 packageManagerInternal.setLocationPackagesProvider(
263 new PackageManagerInternal.PackagesProvider() {
264 @Override
265 public String[] getPackages(int userId) {
266 return mContext.getResources().getStringArray(
267 com.android.internal.R.array.config_locationProviderPackageNames);
268 }
269 });
270
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700271 if (D) Log.d(TAG, "Constructed");
272
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700273 // most startup is deferred until systemRunning()
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700274 }
275
Svetoslav Ganova0027152013-06-25 14:59:53 -0700276 public void systemRunning() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700277 synchronized (mLock) {
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700278 if (D) Log.d(TAG, "systemRunning()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700279
Victoria Lease5cd731a2012-12-19 15:04:21 -0800280 // fetch package manager
281 mPackageManager = mContext.getPackageManager();
282
Victoria Lease0aa28602013-05-29 15:28:26 -0700283 // fetch power manager
284 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800285
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800286 // fetch activity manager
287 mActivityManager
288 = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
289
Victoria Lease5cd731a2012-12-19 15:04:21 -0800290 // prepare worker thread
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700291 mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
Victoria Lease5cd731a2012-12-19 15:04:21 -0800292
293 // prepare mLocationHandler's dependents
294 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
295 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
296 mBlacklist.init();
297 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
298
Dianne Hackbornc2293022013-02-06 23:14:49 -0800299 // Monitor for app ops mode changes.
Dianne Hackborn9bb0ee92013-09-22 12:31:38 -0700300 AppOpsManager.OnOpChangedListener callback
301 = new AppOpsManager.OnOpChangedInternalListener() {
302 public void onOpChanged(int op, String packageName) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800303 synchronized (mLock) {
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700304 for (Receiver receiver : mReceivers.values()) {
305 receiver.updateMonitoring(true);
306 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800307 applyAllProviderRequirementsLocked();
308 }
309 }
310 };
311 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
312
David Christieb870dbf2015-06-22 12:42:53 -0700313 PackageManager.OnPermissionsChangedListener permissionListener
314 = new PackageManager.OnPermissionsChangedListener() {
315 @Override
316 public void onPermissionsChanged(final int uid) {
317 synchronized (mLock) {
318 applyAllProviderRequirementsLocked();
319 }
320 }
321 };
322 mPackageManager.addOnPermissionsChangeListener(permissionListener);
323
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800324 // listen for background/foreground changes
325 ActivityManager.OnUidImportanceListener uidImportanceListener
326 = new ActivityManager.OnUidImportanceListener() {
327 @Override
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700328 public void onUidImportance(final int uid, final int importance) {
329 mLocationHandler.post(new Runnable() {
330 @Override
331 public void run() {
332 onUidImportanceChanged(uid, importance);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800333 }
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700334 });
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800335 }
336 };
337 mActivityManager.addOnUidImportanceListener(uidImportanceListener,
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700338 FOREGROUND_IMPORTANCE_CUTOFF);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800339
Amith Yamasanib27528d2014-06-05 15:02:10 -0700340 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
341 updateUserProfiles(mCurrentUserId);
342
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800343 updateBackgroundThrottlingWhitelistLocked();
Soonil Nagarkar2b565df2017-02-14 13:33:23 -0800344
Victoria Lease5cd731a2012-12-19 15:04:21 -0800345 // prepare providers
346 loadProvidersLocked();
347 updateProvidersLocked();
348 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700349
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700350 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700351 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700352 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700353 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800354 @Override
355 public void onChange(boolean selfChange) {
356 synchronized (mLock) {
357 updateProvidersLocked();
358 }
359 }
360 }, UserHandle.USER_ALL);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800361 mContext.getContentResolver().registerContentObserver(
362 Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS),
363 true,
364 new ContentObserver(mLocationHandler) {
365 @Override
366 public void onChange(boolean selfChange) {
367 synchronized (mLock) {
368 updateProvidersLocked();
369 }
370 }
371 }, UserHandle.USER_ALL);
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800372 mContext.getContentResolver().registerContentObserver(
gomo48f1a642017-11-10 20:35:46 -0800373 Settings.Global.getUriFor(
374 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
375 true,
376 new ContentObserver(mLocationHandler) {
377 @Override
378 public void onChange(boolean selfChange) {
379 synchronized (mLock) {
380 updateBackgroundThrottlingWhitelistLocked();
381 updateProvidersLocked();
382 }
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800383 }
gomo48f1a642017-11-10 20:35:46 -0800384 }, UserHandle.USER_ALL);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800385 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700386
Victoria Lease38389b62012-09-30 11:44:22 -0700387 // listen for user change
388 IntentFilter intentFilter = new IntentFilter();
389 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700390 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
391 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
destradaab9026982015-08-27 17:34:54 -0700392 intentFilter.addAction(Intent.ACTION_SHUTDOWN);
Victoria Lease38389b62012-09-30 11:44:22 -0700393
394 mContext.registerReceiverAsUser(new BroadcastReceiver() {
395 @Override
396 public void onReceive(Context context, Intent intent) {
397 String action = intent.getAction();
398 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
399 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
Amith Yamasanib27528d2014-06-05 15:02:10 -0700400 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
401 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
402 updateUserProfiles(mCurrentUserId);
destradaab9026982015-08-27 17:34:54 -0700403 } else if (Intent.ACTION_SHUTDOWN.equals(action)) {
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700404 // shutdown only if UserId indicates whole system, not just one user
gomo48f1a642017-11-10 20:35:46 -0800405 if (D) Log.d(TAG, "Shutdown received with UserId: " + getSendingUserId());
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700406 if (getSendingUserId() == UserHandle.USER_ALL) {
407 shutdownComponents();
408 }
Victoria Lease38389b62012-09-30 11:44:22 -0700409 }
410 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800411 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700412 }
413
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700414 private void onUidImportanceChanged(int uid, int importance) {
415 boolean foreground = isImportanceForeground(importance);
416 HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
417 synchronized (mLock) {
418 for (Entry<String, ArrayList<UpdateRecord>> entry
gomo48f1a642017-11-10 20:35:46 -0800419 : mRecordsByProvider.entrySet()) {
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700420 String provider = entry.getKey();
421 for (UpdateRecord record : entry.getValue()) {
422 if (record.mReceiver.mIdentity.mUid == uid
gomo48f1a642017-11-10 20:35:46 -0800423 && record.mIsForegroundUid != foreground) {
424 if (D) {
425 Log.d(TAG, "request from uid " + uid + " is now "
426 + (foreground ? "foreground" : "background)"));
427 }
Wyatt Rileyf7075e02018-04-12 17:54:26 -0700428 record.updateForeground(foreground);
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700429
430 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
431 affectedProviders.add(provider);
432 }
433 }
434 }
435 }
436 for (String provider : affectedProviders) {
437 applyRequirementsLocked(provider);
438 }
439
Wyatt Riley11cc7492018-01-17 08:48:27 -0800440 for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700441 if (entry.getValue().mUid == uid) {
gomo48f1a642017-11-10 20:35:46 -0800442 if (D) {
443 Log.d(TAG, "gnss measurements listener from uid " + uid
444 + " is now " + (foreground ? "foreground" : "background)"));
445 }
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700446 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800447 mGnssMeasurementsProvider.addListener(
448 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700449 } else {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800450 mGnssMeasurementsProvider.removeListener(
451 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700452 }
453 }
454 }
455
Wyatt Riley11cc7492018-01-17 08:48:27 -0800456 for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700457 if (entry.getValue().mUid == uid) {
gomo48f1a642017-11-10 20:35:46 -0800458 if (D) {
459 Log.d(TAG, "gnss navigation message listener from uid "
460 + uid + " is now "
461 + (foreground ? "foreground" : "background)"));
462 }
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700463 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800464 mGnssNavigationMessageProvider.addListener(
465 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700466 } else {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800467 mGnssNavigationMessageProvider.removeListener(
468 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700469 }
470 }
471 }
472 }
473 }
474
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800475 private static boolean isImportanceForeground(int importance) {
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700476 return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800477 }
478
Amith Yamasanib27528d2014-06-05 15:02:10 -0700479 /**
destradaab9026982015-08-27 17:34:54 -0700480 * Provides a way for components held by the {@link LocationManagerService} to clean-up
481 * gracefully on system's shutdown.
482 *
483 * NOTES:
484 * 1) Only provides a chance to clean-up on an opt-in basis. This guarantees back-compat
485 * support for components that do not wish to handle such event.
486 */
487 private void shutdownComponents() {
gomo48f1a642017-11-10 20:35:46 -0800488 if (D) Log.d(TAG, "Shutting down components...");
destradaab9026982015-08-27 17:34:54 -0700489
490 LocationProviderInterface gpsProvider = mProvidersByName.get(LocationManager.GPS_PROVIDER);
491 if (gpsProvider != null && gpsProvider.isEnabled()) {
492 gpsProvider.disable();
493 }
destradaab9026982015-08-27 17:34:54 -0700494 }
495
496 /**
Amith Yamasanib27528d2014-06-05 15:02:10 -0700497 * Makes a list of userids that are related to the current user. This is
498 * relevant when using managed profiles. Otherwise the list only contains
499 * the current user.
500 *
501 * @param currentUserId the current user, who might have an alter-ego.
502 */
503 void updateUserProfiles(int currentUserId) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700504 int[] profileIds = mUserManager.getProfileIdsWithDisabled(currentUserId);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700505 synchronized (mLock) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700506 mCurrentUserProfiles = profileIds;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700507 }
508 }
509
510 /**
511 * Checks if the specified userId matches any of the current foreground
512 * users stored in mCurrentUserProfiles.
513 */
514 private boolean isCurrentProfile(int userId) {
515 synchronized (mLock) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700516 return ArrayUtils.contains(mCurrentUserProfiles, userId);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700517 }
518 }
519
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500520 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
521 PackageManager pm = mContext.getPackageManager();
522 String systemPackageName = mContext.getPackageName();
523 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
524
525 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
526 new Intent(FUSED_LOCATION_SERVICE_ACTION),
527 PackageManager.GET_META_DATA, mCurrentUserId);
528 for (ResolveInfo rInfo : rInfos) {
529 String packageName = rInfo.serviceInfo.packageName;
530
531 // Check that the signature is in the list of supported sigs. If it's not in
532 // this list the standard provider binding logic won't bind to it.
533 try {
534 PackageInfo pInfo;
535 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
536 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
537 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
538 ", but has wrong signature, ignoring");
539 continue;
540 }
541 } catch (NameNotFoundException e) {
542 Log.e(TAG, "missing package: " + packageName);
543 continue;
544 }
545
546 // Get the version info
547 if (rInfo.serviceInfo.metaData == null) {
548 Log.w(TAG, "Found fused provider without metadata: " + packageName);
549 continue;
550 }
551
552 int version = rInfo.serviceInfo.metaData.getInt(
553 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
554 if (version == 0) {
555 // This should be the fallback fused location provider.
556
557 // Make sure it's in the system partition.
558 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
559 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
560 continue;
561 }
562
563 // Check that the fallback is signed the same as the OS
564 // as a proxy for coreApp="true"
565 if (pm.checkSignatures(systemPackageName, packageName)
566 != PackageManager.SIGNATURE_MATCH) {
gomo48f1a642017-11-10 20:35:46 -0800567 if (D) {
568 Log.d(TAG, "Fallback candidate not signed the same as system: "
569 + packageName);
570 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500571 continue;
572 }
573
574 // Found a valid fallback.
575 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
576 return;
577 } else {
578 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
579 }
580 }
581
582 throw new IllegalStateException("Unable to find a fused location provider that is in the "
583 + "system partition with version 0 and signed with the platform certificate. "
584 + "Such a package is needed to provide a default fused location provider in the "
585 + "event that no other fused location provider has been installed or is currently "
586 + "available. For example, coreOnly boot mode when decrypting the data "
587 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
588 }
589
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700590 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700591 // create a passive location provider, which is always enabled
592 PassiveProvider passiveProvider = new PassiveProvider(this);
593 addProviderLocked(passiveProvider);
594 mEnabledProviders.add(passiveProvider.getName());
595 mPassiveProvider = passiveProvider;
596
Lifu Tang30f95a72016-01-07 23:20:38 -0800597 if (GnssLocationProvider.isSupported()) {
Wei Liu5241a4c2015-05-11 14:00:36 -0700598 // Create a gps location provider
Lifu Tang30f95a72016-01-07 23:20:38 -0800599 GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext, this,
Wei Liu5241a4c2015-05-11 14:00:36 -0700600 mLocationHandler.getLooper());
Lifu Tang9363b942016-02-16 18:07:00 -0800601 mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
Wyatt Rileycf879db2017-01-12 13:57:38 -0800602 mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
Siddharth Raybb608c82017-03-16 11:33:34 -0700603 mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800604 mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
605 mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
606 addProviderLocked(gnssProvider);
607 mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProvider);
Lifu Tang818aa2c2016-02-01 01:52:00 -0800608 mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
609 mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800610 mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700611 }
612
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700613 /*
614 Load package name(s) containing location provider support.
615 These packages can contain services implementing location providers:
616 Geocoder Provider, Network Location Provider, and
617 Fused Location Provider. They will each be searched for
618 service components implementing these providers.
619 The location framework also has support for installation
620 of new location providers at run-time. The new package does not
621 have to be explicitly listed here, however it must have a signature
622 that matches the signature of at least one package on this list.
623 */
624 Resources resources = mContext.getResources();
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800625 ArrayList<String> providerPackageNames = new ArrayList<>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500626 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700627 com.android.internal.R.array.config_locationProviderPackageNames);
gomo48f1a642017-11-10 20:35:46 -0800628 if (D) {
629 Log.d(TAG, "certificates for location providers pulled from: " +
630 Arrays.toString(pkgs));
631 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500632 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
633
634 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700635
636 // bind to network provider
637 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
638 mContext,
639 LocationManager.NETWORK_PROVIDER,
640 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700641 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
642 com.android.internal.R.string.config_networkLocationProviderPackageName,
643 com.android.internal.R.array.config_locationProviderPackageNames,
644 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700645 if (networkProvider != null) {
646 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
647 mProxyProviders.add(networkProvider);
648 addProviderLocked(networkProvider);
649 } else {
gomo48f1a642017-11-10 20:35:46 -0800650 Slog.w(TAG, "no network location provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700651 }
652
653 // bind to fused provider
654 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
655 mContext,
656 LocationManager.FUSED_PROVIDER,
657 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700658 com.android.internal.R.bool.config_enableFusedLocationOverlay,
659 com.android.internal.R.string.config_fusedLocationProviderPackageName,
660 com.android.internal.R.array.config_locationProviderPackageNames,
661 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700662 if (fusedLocationProvider != null) {
663 addProviderLocked(fusedLocationProvider);
664 mProxyProviders.add(fusedLocationProvider);
665 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700666 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700667 } else {
668 Slog.e(TAG, "no fused location provider found",
669 new IllegalStateException("Location service needs a fused location provider"));
670 }
671
672 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700673 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
674 com.android.internal.R.bool.config_enableGeocoderOverlay,
675 com.android.internal.R.string.config_geocoderProviderPackageName,
676 com.android.internal.R.array.config_locationProviderPackageNames,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800677 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700678 if (mGeocodeProvider == null) {
gomo48f1a642017-11-10 20:35:46 -0800679 Slog.e(TAG, "no geocoder provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700680 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700681
destradaaf9a274c2014-07-25 15:11:56 -0700682 // bind to geofence provider
683 GeofenceProxy provider = GeofenceProxy.createAndBind(
gomo48f1a642017-11-10 20:35:46 -0800684 mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
destradaaf9a274c2014-07-25 15:11:56 -0700685 com.android.internal.R.string.config_geofenceProviderPackageName,
686 com.android.internal.R.array.config_locationProviderPackageNames,
687 mLocationHandler,
Wei Liu5241a4c2015-05-11 14:00:36 -0700688 mGpsGeofenceProxy,
Jiyong Park4cc3a1c2018-03-08 16:43:07 +0900689 null);
destradaaf9a274c2014-07-25 15:11:56 -0700690 if (provider == null) {
gomo48f1a642017-11-10 20:35:46 -0800691 Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
destradaa0682809a2013-08-12 18:50:30 -0700692 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900693
destradaa6e2fe752015-06-23 17:25:53 -0700694 // bind to hardware activity recognition
695 boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported();
696 ActivityRecognitionHardware activityRecognitionHardware = null;
697 if (activityRecognitionHardwareIsSupported) {
698 activityRecognitionHardware = ActivityRecognitionHardware.getInstance(mContext);
destradaaa4fa3b52014-07-09 10:46:39 -0700699 } else {
destradaa6b4893a2016-05-03 15:33:43 -0700700 Slog.d(TAG, "Hardware Activity-Recognition not supported.");
destradaaa4fa3b52014-07-09 10:46:39 -0700701 }
destradaa6e2fe752015-06-23 17:25:53 -0700702 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
703 mContext,
704 mLocationHandler,
705 activityRecognitionHardwareIsSupported,
706 activityRecognitionHardware,
707 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
708 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
709 com.android.internal.R.array.config_locationProviderPackageNames);
710 if (proxy == null) {
destradaa6b4893a2016-05-03 15:33:43 -0700711 Slog.d(TAG, "Unable to bind ActivityRecognitionProxy.");
destradaa6e2fe752015-06-23 17:25:53 -0700712 }
destradaaa4fa3b52014-07-09 10:46:39 -0700713
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900714 String[] testProviderStrings = resources.getStringArray(
715 com.android.internal.R.array.config_testLocationProviders);
716 for (String testProviderString : testProviderStrings) {
717 String fragments[] = testProviderString.split(",");
718 String name = fragments[0].trim();
719 if (mProvidersByName.get(name) != null) {
720 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
721 }
722 ProviderProperties properties = new ProviderProperties(
723 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
724 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
725 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
726 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
727 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
728 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
729 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
730 Integer.parseInt(fragments[8]) /* powerRequirement */,
731 Integer.parseInt(fragments[9]) /* accuracy */);
732 addTestProviderLocked(name, properties);
733 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700734 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700735
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700737 * Called when the device's active user changes.
gomo48f1a642017-11-10 20:35:46 -0800738 *
Victoria Lease38389b62012-09-30 11:44:22 -0700739 * @param userId the new active user's UserId
740 */
741 private void switchUser(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800742 if (mCurrentUserId == userId) {
743 return;
744 }
Victoria Lease83762d22012-10-03 13:51:17 -0700745 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800746 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700747 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700748 mLastLocation.clear();
David Christie1b9b7b12013-04-15 15:31:11 -0700749 mLastLocationCoarseInterval.clear();
Victoria Leaseb711d572012-10-02 13:14:11 -0700750 for (LocationProviderInterface p : mProviders) {
Amith Yamasanib27528d2014-06-05 15:02:10 -0700751 updateProviderListenersLocked(p.getName(), false);
Victoria Leaseb711d572012-10-02 13:14:11 -0700752 }
Victoria Lease38389b62012-09-30 11:44:22 -0700753 mCurrentUserId = userId;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700754 updateUserProfiles(userId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700755 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700756 }
757 }
758
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800759 private static final class Identity {
760 final int mUid;
761 final int mPid;
762 final String mPackageName;
763
764 Identity(int uid, int pid, String packageName) {
765 mUid = uid;
766 mPid = pid;
767 mPackageName = packageName;
768 }
769 }
770
Victoria Lease38389b62012-09-30 11:44:22 -0700771 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
773 * location updates.
774 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700775 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800776 final Identity mIdentity;
Victoria Lease37425c32012-10-16 16:08:48 -0700777 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700778
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779 final ILocationListener mListener;
780 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -0700781 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
David Christie40e57822013-07-30 11:36:48 -0700782 final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700784
gomo48f1a642017-11-10 20:35:46 -0800785 final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700786
David Christie0b837452013-07-29 16:02:13 -0700787 // True if app ops has started monitoring this receiver for locations.
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700788 boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -0700789 // True if app ops has started monitoring this receiver for high power (gps) locations.
790 boolean mOpHighPowerMonitoring;
Mike Lockwood48f17512009-04-23 09:12:08 -0700791 int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -0700792 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700794 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -0700795 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700798 if (listener != null) {
799 mKey = listener.asBinder();
800 } else {
801 mKey = intent;
802 }
Victoria Lease37425c32012-10-16 16:08:48 -0700803 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800804 mIdentity = new Identity(uid, pid, packageName);
Narayan Kamath32684dd2018-01-08 17:32:51 +0000805 if (workSource != null && workSource.isEmpty()) {
David Christie82edc9b2013-07-19 11:31:42 -0700806 workSource = null;
807 }
808 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -0700809 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -0700810
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700811 updateMonitoring(true);
812
Victoria Lease0aa28602013-05-29 15:28:26 -0700813 // construct/configure wakelock
814 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -0700815 if (workSource == null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800816 workSource = new WorkSource(mIdentity.mUid, mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -0700817 }
818 mWakeLock.setWorkSource(workSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 }
820
821 @Override
822 public boolean equals(Object otherObj) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800823 return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 }
825
826 @Override
827 public int hashCode() {
828 return mKey.hashCode();
829 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400830
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831 @Override
832 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700833 StringBuilder s = new StringBuilder();
834 s.append("Reciever[");
835 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700837 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700839 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800840 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700841 for (String p : mUpdateRecords.keySet()) {
842 s.append(" ").append(mUpdateRecords.get(p).toString());
843 }
844 s.append("]");
845 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 }
847
David Christie15b31912013-08-13 15:54:32 -0700848 /**
849 * Update AppOp monitoring for this receiver.
850 *
851 * @param allow If true receiver is currently active, if false it's been removed.
852 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700853 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -0700854 if (mHideFromAppOps) {
855 return;
856 }
857
David Christie15b31912013-08-13 15:54:32 -0700858 boolean requestingLocation = false;
859 boolean requestingHighPowerLocation = false;
860 if (allow) {
861 // See if receiver has any enabled update records. Also note if any update records
862 // are high power (has a high power provider with an interval under a threshold).
863 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
864 if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) {
865 requestingLocation = true;
866 LocationProviderInterface locationProvider
David Christie2ff96af2014-01-30 16:09:37 -0800867 = mProvidersByName.get(updateRecord.mProvider);
David Christie15b31912013-08-13 15:54:32 -0700868 ProviderProperties properties = locationProvider != null
869 ? locationProvider.getProperties() : null;
870 if (properties != null
871 && properties.mPowerRequirement == Criteria.POWER_HIGH
872 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
873 requestingHighPowerLocation = true;
874 break;
875 }
876 }
877 }
878 }
879
David Christie0b837452013-07-29 16:02:13 -0700880 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -0700881 mOpMonitoring = updateMonitoring(
882 requestingLocation,
883 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700884 AppOpsManager.OP_MONITOR_LOCATION);
885
886 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -0700887 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -0700888 mOpHighPowerMonitoring = updateMonitoring(
889 requestingHighPowerLocation,
890 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700891 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -0700892 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -0700893 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -0700894 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
895 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
896 }
David Christie0b837452013-07-29 16:02:13 -0700897 }
898
899 /**
900 * Update AppOps monitoring for a single location request and op type.
901 *
gomo48f1a642017-11-10 20:35:46 -0800902 * @param allowMonitoring True if monitoring is allowed for this request/op.
David Christie0b837452013-07-29 16:02:13 -0700903 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
gomo48f1a642017-11-10 20:35:46 -0800904 * @param op AppOps code for the op to update.
David Christie0b837452013-07-29 16:02:13 -0700905 * @return True if monitoring is on for this request/op after updating.
906 */
907 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
908 int op) {
909 if (!currentlyMonitoring) {
910 if (allowMonitoring) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800911 return mAppOps.startOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -0700912 == AppOpsManager.MODE_ALLOWED;
913 }
914 } else {
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800915 if (!allowMonitoring
916 || mAppOps.checkOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -0700917 != AppOpsManager.MODE_ALLOWED) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800918 mAppOps.finishOp(op, mIdentity.mUid, mIdentity.mPackageName);
David Christie0b837452013-07-29 16:02:13 -0700919 return false;
920 }
921 }
922
923 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700924 }
925
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800926 public boolean isListener() {
927 return mListener != null;
928 }
929
930 public boolean isPendingIntent() {
931 return mPendingIntent != null;
932 }
933
934 public ILocationListener getListener() {
935 if (mListener != null) {
936 return mListener;
937 }
938 throw new IllegalStateException("Request for non-existent listener");
939 }
940
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
942 if (mListener != null) {
943 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700944 synchronized (this) {
945 // synchronize to ensure incrementPendingBroadcastsLocked()
946 // is called before decrementPendingBroadcasts()
947 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700948 // call this after broadcasting so we do not increment
949 // if we throw an exeption.
950 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700951 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 } catch (RemoteException e) {
953 return false;
954 }
955 } else {
956 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800957 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
959 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700960 synchronized (this) {
961 // synchronize to ensure incrementPendingBroadcastsLocked()
962 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700963 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -0700964 getResolutionPermission(mAllowedResolutionLevel),
965 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -0700966 // call this after broadcasting so we do not increment
967 // if we throw an exeption.
968 incrementPendingBroadcastsLocked();
969 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 } catch (PendingIntent.CanceledException e) {
971 return false;
972 }
973 }
974 return true;
975 }
976
977 public boolean callLocationChangedLocked(Location location) {
978 if (mListener != null) {
979 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700980 synchronized (this) {
981 // synchronize to ensure incrementPendingBroadcastsLocked()
982 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800983 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700984 // call this after broadcasting so we do not increment
985 // if we throw an exeption.
986 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700987 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 } catch (RemoteException e) {
989 return false;
990 }
991 } else {
992 Intent locationChanged = new Intent();
gomo48f1a642017-11-10 20:35:46 -0800993 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED,
994 new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700996 synchronized (this) {
997 // synchronize to ensure incrementPendingBroadcastsLocked()
998 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700999 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001000 getResolutionPermission(mAllowedResolutionLevel),
1001 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001002 // call this after broadcasting so we do not increment
1003 // if we throw an exeption.
1004 incrementPendingBroadcastsLocked();
1005 }
1006 } catch (PendingIntent.CanceledException e) {
1007 return false;
1008 }
1009 }
1010 return true;
1011 }
1012
1013 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -07001014 // First update AppOp monitoring.
1015 // An app may get/lose location access as providers are enabled/disabled.
1016 updateMonitoring(true);
1017
Mike Lockwood48f17512009-04-23 09:12:08 -07001018 if (mListener != null) {
1019 try {
1020 synchronized (this) {
1021 // synchronize to ensure incrementPendingBroadcastsLocked()
1022 // is called before decrementPendingBroadcasts()
1023 if (enabled) {
1024 mListener.onProviderEnabled(provider);
1025 } else {
1026 mListener.onProviderDisabled(provider);
1027 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001028 // call this after broadcasting so we do not increment
1029 // if we throw an exeption.
1030 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001031 }
1032 } catch (RemoteException e) {
1033 return false;
1034 }
1035 } else {
1036 Intent providerIntent = new Intent();
1037 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
1038 try {
1039 synchronized (this) {
1040 // synchronize to ensure incrementPendingBroadcastsLocked()
1041 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001042 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001043 getResolutionPermission(mAllowedResolutionLevel),
1044 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001045 // call this after broadcasting so we do not increment
1046 // if we throw an exeption.
1047 incrementPendingBroadcastsLocked();
1048 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049 } catch (PendingIntent.CanceledException e) {
1050 return false;
1051 }
1052 }
1053 return true;
1054 }
1055
Nick Pellyf1be6862012-05-15 10:53:42 -07001056 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001058 if (D) Log.d(TAG, "Location listener died");
1059
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001060 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 removeUpdatesLocked(this);
1062 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001063 synchronized (this) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001064 clearPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001065 }
1066 }
1067
Nick Pellye0fd6932012-07-11 10:26:13 -07001068 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001069 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1070 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001071 synchronized (this) {
1072 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001073 }
1074 }
1075
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001076 // this must be called while synchronized by caller in a synchronized block
1077 // containing the sending of the broadcaset
1078 private void incrementPendingBroadcastsLocked() {
1079 if (mPendingBroadcasts++ == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001080 mWakeLock.acquire();
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001081 }
1082 }
1083
1084 private void decrementPendingBroadcastsLocked() {
1085 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001086 if (mWakeLock.isHeld()) {
1087 mWakeLock.release();
1088 }
1089 }
1090 }
1091
1092 public void clearPendingBroadcastsLocked() {
1093 if (mPendingBroadcasts > 0) {
1094 mPendingBroadcasts = 0;
1095 if (mWakeLock.isHeld()) {
1096 mWakeLock.release();
1097 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001098 }
1099 }
1100 }
1101
Nick Pellye0fd6932012-07-11 10:26:13 -07001102 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001103 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001104 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -04001105 //the receiver list if it is not found. If it is not found then the
1106 //LocationListener was removed when it had a pending broadcast and should
1107 //not be added back.
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001108 synchronized (mLock) {
1109 IBinder binder = listener.asBinder();
1110 Receiver receiver = mReceivers.get(binder);
1111 if (receiver != null) {
1112 synchronized (receiver) {
1113 // so wakelock calls will succeed
1114 long identity = Binder.clearCallingIdentity();
1115 receiver.decrementPendingBroadcastsLocked();
1116 Binder.restoreCallingIdentity(identity);
David Christie2ff96af2014-01-30 16:09:37 -08001117 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001118 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001119 }
1120 }
1121
Lifu Tang82f893d2016-01-21 18:15:33 -08001122 /**
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001123 * Returns the year of the GNSS hardware.
Lifu Tang82f893d2016-01-21 18:15:33 -08001124 */
1125 @Override
Lifu Tang9363b942016-02-16 18:07:00 -08001126 public int getGnssYearOfHardware() {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001127 if (mGnssSystemInfoProvider != null) {
Lifu Tang9363b942016-02-16 18:07:00 -08001128 return mGnssSystemInfoProvider.getGnssYearOfHardware();
Lifu Tang82f893d2016-01-21 18:15:33 -08001129 } else {
1130 return 0;
1131 }
1132 }
1133
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001134
1135 /**
1136 * Returns the model name of the GNSS hardware.
1137 */
1138 @Override
Wyatt Riley49097c02018-03-15 09:14:43 -07001139 @Nullable
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001140 public String getGnssHardwareModelName() {
1141 if (mGnssSystemInfoProvider != null) {
1142 return mGnssSystemInfoProvider.getGnssHardwareModelName();
1143 } else {
Wyatt Riley49097c02018-03-15 09:14:43 -07001144 return null;
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001145 }
1146 }
1147
Wyatt Rileycf879db2017-01-12 13:57:38 -08001148 /**
1149 * Runs some checks for GNSS (FINE) level permissions, used by several methods which directly
1150 * (try to) access GNSS information at this layer.
1151 */
1152 private boolean hasGnssPermissions(String packageName) {
1153 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1154 checkResolutionLevelIsSufficientForProviderUse(
1155 allowedResolutionLevel,
1156 LocationManager.GPS_PROVIDER);
1157
1158 int pid = Binder.getCallingPid();
1159 int uid = Binder.getCallingUid();
1160 long identity = Binder.clearCallingIdentity();
1161 boolean hasLocationAccess;
1162 try {
1163 hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1164 } finally {
1165 Binder.restoreCallingIdentity(identity);
1166 }
1167
1168 return hasLocationAccess;
1169 }
1170
1171 /**
1172 * Returns the GNSS batching size, if available.
1173 */
1174 @Override
1175 public int getGnssBatchSize(String packageName) {
1176 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1177 "Location Hardware permission not granted to access hardware batching");
1178
1179 if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
Yu-Han Yang3557cc72018-03-21 12:48:36 -07001180 return mGnssBatchingProvider.getBatchSize();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001181 } else {
1182 return 0;
1183 }
1184 }
1185
1186 /**
1187 * Adds a callback for GNSS Batching events, if permissions allow, which are transported
1188 * to potentially multiple listeners by the BatchedLocationCallbackTransport above this.
1189 */
1190 @Override
1191 public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
1192 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1193 "Location Hardware permission not granted to access hardware batching");
1194
1195 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1196 return false;
1197 }
1198
1199 mGnssBatchingCallback = callback;
1200 mGnssBatchingDeathCallback = new LinkedCallback(callback);
1201 try {
1202 callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
1203 } catch (RemoteException e) {
1204 // if the remote process registering the listener is already dead, just swallow the
1205 // exception and return
1206 Log.e(TAG, "Remote listener already died.", e);
1207 return false;
1208 }
1209
1210 return true;
1211 }
1212
1213 private class LinkedCallback implements IBinder.DeathRecipient {
1214 private final IBatchedLocationCallback mCallback;
1215
1216 public LinkedCallback(@NonNull IBatchedLocationCallback callback) {
1217 mCallback = callback;
1218 }
1219
1220 @NonNull
1221 public IBatchedLocationCallback getUnderlyingListener() {
1222 return mCallback;
1223 }
1224
1225 @Override
1226 public void binderDied() {
1227 Log.d(TAG, "Remote Batching Callback died: " + mCallback);
1228 stopGnssBatch();
1229 removeGnssBatchingCallback();
1230 }
1231 }
1232
1233 /**
1234 * Removes callback for GNSS batching
1235 */
1236 @Override
1237 public void removeGnssBatchingCallback() {
1238 try {
1239 mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
1240 0 /* flags */);
1241 } catch (NoSuchElementException e) {
1242 // if the death callback isn't connected (it should be...), log error, swallow the
1243 // exception and return
1244 Log.e(TAG, "Couldn't unlink death callback.", e);
1245 }
1246 mGnssBatchingCallback = null;
1247 mGnssBatchingDeathCallback = null;
1248 }
1249
1250
1251 /**
1252 * Starts GNSS batching, if available.
1253 */
1254 @Override
1255 public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
1256 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1257 "Location Hardware permission not granted to access hardware batching");
1258
1259 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1260 return false;
1261 }
1262
1263 if (mGnssBatchingInProgress) {
1264 // Current design does not expect multiple starts to be called repeatedly
1265 Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
1266 // Try to clean up anyway, and continue
1267 stopGnssBatch();
1268 }
1269
1270 mGnssBatchingInProgress = true;
1271 return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
1272 }
1273
1274 /**
1275 * Flushes a GNSS batch in progress
1276 */
1277 @Override
1278 public void flushGnssBatch(String packageName) {
1279 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1280 "Location Hardware permission not granted to access hardware batching");
1281
1282 if (!hasGnssPermissions(packageName)) {
1283 Log.e(TAG, "flushGnssBatch called without GNSS permissions");
1284 return;
1285 }
1286
1287 if (!mGnssBatchingInProgress) {
1288 Log.w(TAG, "flushGnssBatch called with no batch in progress");
1289 }
1290
1291 if (mGnssBatchingProvider != null) {
gomo48f1a642017-11-10 20:35:46 -08001292 mGnssBatchingProvider.flush();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001293 }
1294 }
1295
1296 /**
1297 * Stops GNSS batching
1298 */
1299 @Override
1300 public boolean stopGnssBatch() {
1301 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1302 "Location Hardware permission not granted to access hardware batching");
1303
1304 if (mGnssBatchingProvider != null) {
1305 mGnssBatchingInProgress = false;
1306 return mGnssBatchingProvider.stop();
gomo48f1a642017-11-10 20:35:46 -08001307 } else {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001308 return false;
1309 }
1310 }
1311
1312 @Override
1313 public void reportLocationBatch(List<Location> locations) {
1314 checkCallerIsProvider();
1315
1316 // Currently used only for GNSS locations - update permissions check if changed
1317 if (isAllowedByCurrentUserSettingsLocked(LocationManager.GPS_PROVIDER)) {
1318 if (mGnssBatchingCallback == null) {
1319 Slog.e(TAG, "reportLocationBatch() called without active Callback");
1320 return;
1321 }
1322 try {
1323 mGnssBatchingCallback.onLocationBatch(locations);
1324 } catch (RemoteException e) {
1325 Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
1326 }
1327 } else {
1328 Slog.w(TAG, "reportLocationBatch() called without user permission, locations blocked");
1329 }
1330 }
1331
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001332 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001333 mProviders.add(provider);
1334 mProvidersByName.put(provider.getName(), provider);
1335 }
1336
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001337 private void removeProviderLocked(LocationProviderInterface provider) {
1338 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001339 mProviders.remove(provider);
1340 mProvidersByName.remove(provider.getName());
1341 }
1342
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001343 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -08001344 * Returns "true" if access to the specified location provider is allowed by the current
1345 * user's settings. Access to all location providers is forbidden to non-location-provider
1346 * processes belonging to background users.
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001347 *
1348 * @param provider the name of the location provider
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001349 */
Victoria Lease09eeaec2013-02-05 11:34:13 -08001350 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
Maggie2a9409e2018-03-21 11:47:28 -07001351 return isAllowedByUserSettingsLockedForUser(provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001352 }
1353
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001354 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -08001355 * Returns "true" if access to the specified location provider is allowed by the specified
1356 * user's settings. Access to all location providers is forbidden to non-location-provider
1357 * processes belonging to background users.
1358 *
1359 * @param provider the name of the location provider
Maggie2a9409e2018-03-21 11:47:28 -07001360 * @param userId the user id to query
Victoria Lease09eeaec2013-02-05 11:34:13 -08001361 */
Maggie2a9409e2018-03-21 11:47:28 -07001362 private boolean isAllowedByUserSettingsLockedForUser(String provider, int userId) {
1363 if (mEnabledProviders.contains(provider)) {
1364 return true;
1365 }
1366 if (mDisabledProviders.contains(provider)) {
1367 return false;
1368 }
1369 return isLocationProviderEnabledForUser(provider, userId);
1370 }
1371
1372
1373 /**
1374 * Returns "true" if access to the specified location provider is allowed by the specified
1375 * user's settings. Access to all location providers is forbidden to non-location-provider
1376 * processes belonging to background users.
1377 *
1378 * @param provider the name of the location provider
1379 * @param uid the requestor's UID
1380 * @param userId the user id to query
1381 */
1382 private boolean isAllowedByUserSettingsLocked(String provider, int uid, int userId) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001383 if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001384 return false;
1385 }
Maggie2a9409e2018-03-21 11:47:28 -07001386 return isAllowedByUserSettingsLockedForUser(provider, userId);
Victoria Lease09eeaec2013-02-05 11:34:13 -08001387 }
1388
1389 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001390 * Returns the permission string associated with the specified resolution level.
1391 *
1392 * @param resolutionLevel the resolution level
1393 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001394 */
Victoria Lease37425c32012-10-16 16:08:48 -07001395 private String getResolutionPermission(int resolutionLevel) {
1396 switch (resolutionLevel) {
1397 case RESOLUTION_LEVEL_FINE:
1398 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1399 case RESOLUTION_LEVEL_COARSE:
1400 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1401 default:
1402 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001403 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001404 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001405
Victoria Leaseda479c52012-10-15 15:24:16 -07001406 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001407 * Returns the resolution level allowed to the given PID/UID pair.
1408 *
1409 * @param pid the PID
1410 * @param uid the UID
1411 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -07001412 */
Victoria Lease37425c32012-10-16 16:08:48 -07001413 private int getAllowedResolutionLevel(int pid, int uid) {
1414 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001415 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001416 return RESOLUTION_LEVEL_FINE;
1417 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001418 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001419 return RESOLUTION_LEVEL_COARSE;
1420 } else {
1421 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001422 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001423 }
1424
1425 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001426 * Returns the resolution level allowed to the caller
1427 *
1428 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -07001429 */
Victoria Lease37425c32012-10-16 16:08:48 -07001430 private int getCallerAllowedResolutionLevel() {
1431 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1432 }
1433
1434 /**
1435 * Throw SecurityException if specified resolution level is insufficient to use geofences.
1436 *
1437 * @param allowedResolutionLevel resolution level allowed to caller
1438 */
1439 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1440 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001441 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1442 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001443 }
1444
Victoria Lease37425c32012-10-16 16:08:48 -07001445 /**
1446 * Return the minimum resolution level required to use the specified location provider.
1447 *
1448 * @param provider the name of the location provider
1449 * @return minimum resolution level required for provider
1450 */
1451 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001452 if (LocationManager.GPS_PROVIDER.equals(provider) ||
1453 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1454 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001455 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -07001456 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1457 LocationManager.FUSED_PROVIDER.equals(provider)) {
1458 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001459 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001460 } else {
1461 // mock providers
1462 LocationProviderInterface lp = mMockProviders.get(provider);
1463 if (lp != null) {
1464 ProviderProperties properties = lp.getProperties();
1465 if (properties != null) {
1466 if (properties.mRequiresSatellite) {
1467 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001468 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001469 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1470 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001471 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001472 }
1473 }
1474 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001475 }
Victoria Lease37425c32012-10-16 16:08:48 -07001476 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001477 }
1478
Victoria Lease37425c32012-10-16 16:08:48 -07001479 /**
1480 * Throw SecurityException if specified resolution level is insufficient to use the named
1481 * location provider.
1482 *
1483 * @param allowedResolutionLevel resolution level allowed to caller
gomo48f1a642017-11-10 20:35:46 -08001484 * @param providerName the name of the location provider
Victoria Lease37425c32012-10-16 16:08:48 -07001485 */
1486 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1487 String providerName) {
1488 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1489 if (allowedResolutionLevel < requiredResolutionLevel) {
1490 switch (requiredResolutionLevel) {
1491 case RESOLUTION_LEVEL_FINE:
1492 throw new SecurityException("\"" + providerName + "\" location provider " +
1493 "requires ACCESS_FINE_LOCATION permission.");
1494 case RESOLUTION_LEVEL_COARSE:
1495 throw new SecurityException("\"" + providerName + "\" location provider " +
1496 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1497 default:
1498 throw new SecurityException("Insufficient permission for \"" + providerName +
1499 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001500 }
1501 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001502 }
1503
David Christie82edc9b2013-07-19 11:31:42 -07001504 /**
1505 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
1506 * for battery).
1507 */
David Christie40e57822013-07-30 11:36:48 -07001508 private void checkDeviceStatsAllowed() {
David Christie82edc9b2013-07-19 11:31:42 -07001509 mContext.enforceCallingOrSelfPermission(
1510 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
1511 }
1512
David Christie40e57822013-07-30 11:36:48 -07001513 private void checkUpdateAppOpsAllowed() {
1514 mContext.enforceCallingOrSelfPermission(
1515 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
1516 }
1517
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001518 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001519 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1520 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001521 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001522 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001523 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001524 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001525 }
1526 return -1;
1527 }
1528
David Christieb870dbf2015-06-22 12:42:53 -07001529 boolean reportLocationAccessNoThrow(
1530 int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001531 int op = resolutionLevelToOp(allowedResolutionLevel);
1532 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001533 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1534 return false;
1535 }
1536 }
David Christieb870dbf2015-06-22 12:42:53 -07001537
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001538 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001539 }
1540
David Christieb870dbf2015-06-22 12:42:53 -07001541 boolean checkLocationAccess(int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001542 int op = resolutionLevelToOp(allowedResolutionLevel);
1543 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001544 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1545 return false;
1546 }
1547 }
David Christieb870dbf2015-06-22 12:42:53 -07001548
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001549 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001550 }
1551
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001552 /**
Maggie91e630c2018-01-24 17:31:46 -08001553 * Returns all providers by name, including passive and the ones that are not permitted to
1554 * be accessed by the calling activity or are currently disabled, but excluding fused.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001555 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001556 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001557 public List<String> getAllProviders() {
Maggie91e630c2018-01-24 17:31:46 -08001558 ArrayList<String> out;
1559 synchronized (mLock) {
1560 out = new ArrayList<>(mProviders.size());
1561 for (LocationProviderInterface provider : mProviders) {
1562 String name = provider.getName();
1563 if (LocationManager.FUSED_PROVIDER.equals(name)) {
1564 continue;
1565 }
1566 out.add(name);
1567 }
1568 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001569 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001570 return out;
1571 }
1572
Mike Lockwood03ca2162010-04-01 08:10:09 -07001573 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001574 * Return all providers by name, that match criteria and are optionally
1575 * enabled.
1576 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001577 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001578 @Override
1579 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001580 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001581 ArrayList<String> out;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001582 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07001583 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001584 try {
1585 synchronized (mLock) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001586 out = new ArrayList<>(mProviders.size());
Victoria Leaseb711d572012-10-02 13:14:11 -07001587 for (LocationProviderInterface provider : mProviders) {
1588 String name = provider.getName();
1589 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001590 continue;
1591 }
Victoria Lease37425c32012-10-16 16:08:48 -07001592 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Maggie2a9409e2018-03-21 11:47:28 -07001593 if (enabledOnly
1594 && !isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001595 continue;
1596 }
1597 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
1598 name, provider.getProperties(), criteria)) {
1599 continue;
1600 }
1601 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001602 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001603 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001604 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001605 } finally {
1606 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001607 }
1608
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001609 if (D) Log.d(TAG, "getProviders()=" + out);
1610 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001611 }
1612
1613 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001614 * Return the name of the best provider given a Criteria object.
1615 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001616 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001617 * has been deprecated as well. So this method now uses
1618 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001619 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001620 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001621 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001622 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001623
1624 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001625 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001626 result = pickBest(providers);
1627 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1628 return result;
1629 }
1630 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001631 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001632 result = pickBest(providers);
1633 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1634 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001635 }
1636
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001637 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001638 return null;
1639 }
1640
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001641 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -07001642 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001643 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -07001644 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1645 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001646 } else {
1647 return providers.get(0);
1648 }
1649 }
1650
Nick Pellye0fd6932012-07-11 10:26:13 -07001651 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001652 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1653 LocationProviderInterface p = mProvidersByName.get(provider);
1654 if (p == null) {
1655 throw new IllegalArgumentException("provider=" + provider);
1656 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001657
1658 boolean result = LocationProvider.propertiesMeetCriteria(
1659 p.getName(), p.getProperties(), criteria);
1660 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1661 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001662 }
1663
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001664 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001665 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001666 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001667 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001668 boolean isEnabled = p.isEnabled();
1669 String name = p.getName();
Victoria Lease09eeaec2013-02-05 11:34:13 -08001670 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 if (isEnabled && !shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001672 updateProviderListenersLocked(name, false);
David Christieb084fef2013-12-18 14:33:57 -08001673 // If any provider has been disabled, clear all last locations for all providers.
1674 // This is to be on the safe side in case a provider has location derived from
1675 // this disabled provider.
1676 mLastLocation.clear();
1677 mLastLocationCoarseInterval.clear();
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001678 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001679 } else if (!isEnabled && shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001680 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001681 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001683 }
1684 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001685 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1686 UserHandle.ALL);
Tom O'Neill40a86c22013-09-03 18:05:13 -07001687 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1688 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001689 }
1690 }
1691
Amith Yamasanib27528d2014-06-05 15:02:10 -07001692 private void updateProviderListenersLocked(String provider, boolean enabled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001693 int listeners = 0;
1694
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001695 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001696 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001697
1698 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001699
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001700 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1701 if (records != null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001702 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001703 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001704 // Sends a notification message to the receiver
1705 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1706 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001707 deadReceivers = new ArrayList<>();
Victoria Leaseb711d572012-10-02 13:14:11 -07001708 }
1709 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001710 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001711 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 }
1714 }
1715
1716 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001717 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001718 removeUpdatesLocked(deadReceivers.get(i));
1719 }
1720 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001721
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722 if (enabled) {
1723 p.enable();
1724 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001725 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726 }
1727 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001728 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730 }
1731
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001732 private void applyRequirementsLocked(String provider) {
1733 LocationProviderInterface p = mProvidersByName.get(provider);
1734 if (p == null) return;
1735
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001736 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001737 WorkSource worksource = new WorkSource();
1738 ProviderRequest providerRequest = new ProviderRequest();
1739
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001740 ContentResolver resolver = mContext.getContentResolver();
1741 long backgroundThrottleInterval = Settings.Global.getLong(
1742 resolver,
1743 Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
1744 DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
gomo48f1a642017-11-10 20:35:46 -08001745 // initialize the low power mode to true and set to false if any of the records requires
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001746
gomo48f1a642017-11-10 20:35:46 -08001747 providerRequest.lowPowerMode = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001748 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001749 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001750 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
David Christieb870dbf2015-06-22 12:42:53 -07001751 if (checkLocationAccess(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001752 record.mReceiver.mIdentity.mPid,
1753 record.mReceiver.mIdentity.mUid,
1754 record.mReceiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001755 record.mReceiver.mAllowedResolutionLevel)) {
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001756 LocationRequest locationRequest = record.mRealRequest;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001757 long interval = locationRequest.getInterval();
1758
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001759 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001760 if (!record.mIsForegroundUid) {
1761 interval = Math.max(interval, backgroundThrottleInterval);
1762 }
1763 if (interval != locationRequest.getInterval()) {
1764 locationRequest = new LocationRequest(locationRequest);
1765 locationRequest.setInterval(interval);
1766 }
1767 }
1768
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001769 record.mRequest = locationRequest;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001770 providerRequest.locationRequests.add(locationRequest);
gomo48f1a642017-11-10 20:35:46 -08001771 if (!locationRequest.isLowPowerMode()) {
1772 providerRequest.lowPowerMode = false;
1773 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001774 if (interval < providerRequest.interval) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001775 providerRequest.reportLocation = true;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001776 providerRequest.interval = interval;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001777 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001778 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001779 }
1780 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001781
1782 if (providerRequest.reportLocation) {
1783 // calculate who to blame for power
1784 // This is somewhat arbitrary. We pick a threshold interval
1785 // that is slightly higher that the minimum interval, and
1786 // spread the blame across all applications with a request
1787 // under that threshold.
1788 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1789 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001790 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001791 LocationRequest locationRequest = record.mRequest;
Svet Ganove998c732016-06-10 00:12:38 -07001792
1793 // Don't assign battery blame for update records whose
1794 // client has no permission to receive location data.
1795 if (!providerRequest.locationRequests.contains(locationRequest)) {
1796 continue;
1797 }
1798
Victoria Leaseb711d572012-10-02 13:14:11 -07001799 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07001800 if (record.mReceiver.mWorkSource != null
Narayan Kamath32684dd2018-01-08 17:32:51 +00001801 && isValidWorkSource(record.mReceiver.mWorkSource)) {
David Christie82edc9b2013-07-19 11:31:42 -07001802 worksource.add(record.mReceiver.mWorkSource);
1803 } else {
Narayan Kamath32684dd2018-01-08 17:32:51 +00001804 // Assign blame to caller if there's no WorkSource associated with
1805 // the request or if it's invalid.
David Christie82edc9b2013-07-19 11:31:42 -07001806 worksource.add(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001807 record.mReceiver.mIdentity.mUid,
1808 record.mReceiver.mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07001809 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001810 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001811 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001812 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001813 }
1814 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001815
1816 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1817 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001818 }
1819
Narayan Kamath32684dd2018-01-08 17:32:51 +00001820 /**
1821 * Whether a given {@code WorkSource} associated with a Location request is valid.
1822 */
1823 private static boolean isValidWorkSource(WorkSource workSource) {
1824 if (workSource.size() > 0) {
1825 // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
1826 // by tags.
1827 return workSource.getName(0) != null;
1828 } else {
1829 // For now, make sure callers have supplied an attribution tag for use with
1830 // AppOpsManager. This might be relaxed in the future.
1831 final ArrayList<WorkChain> workChains = workSource.getWorkChains();
1832 return workChains != null && !workChains.isEmpty() &&
1833 workChains.get(0).getAttributionTag() != null;
1834 }
1835 }
1836
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001837 @Override
1838 public String[] getBackgroundThrottlingWhitelist() {
1839 synchronized (mLock) {
1840 return mBackgroundThrottlePackageWhitelist.toArray(
gomo48f1a642017-11-10 20:35:46 -08001841 new String[mBackgroundThrottlePackageWhitelist.size()]);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001842 }
1843 }
1844
1845 private void updateBackgroundThrottlingWhitelistLocked() {
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08001846 String setting = Settings.Global.getString(
gomo48f1a642017-11-10 20:35:46 -08001847 mContext.getContentResolver(),
1848 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08001849 if (setting == null) {
1850 setting = "";
1851 }
1852
1853 mBackgroundThrottlePackageWhitelist.clear();
1854 mBackgroundThrottlePackageWhitelist.addAll(
gomo48f1a642017-11-10 20:35:46 -08001855 SystemConfig.getInstance().getAllowUnthrottledLocation());
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08001856 mBackgroundThrottlePackageWhitelist.addAll(
gomo48f1a642017-11-10 20:35:46 -08001857 Arrays.asList(setting.split(",")));
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08001858 }
1859
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001860 private boolean isThrottlingExemptLocked(Identity identity) {
1861 if (identity.mUid == Process.SYSTEM_UID) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001862 return true;
1863 }
1864
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001865 if (mBackgroundThrottlePackageWhitelist.contains(identity.mPackageName)) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001866 return true;
1867 }
1868
1869 for (LocationProviderProxy provider : mProxyProviders) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001870 if (identity.mPackageName.equals(provider.getConnectedPackageName())) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001871 return true;
1872 }
1873 }
1874
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001875 return false;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001876 }
1877
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001878 private class UpdateRecord {
1879 final String mProvider;
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001880 final LocationRequest mRealRequest; // original request from client
1881 LocationRequest mRequest; // possibly throttled version of the request
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001882 final Receiver mReceiver;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001883 boolean mIsForegroundUid;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001884 Location mLastFixBroadcast;
1885 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001886
1887 /**
1888 * Note: must be constructed with lock held.
1889 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001890 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001891 mProvider = provider;
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001892 mRealRequest = request;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001893 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001894 mReceiver = receiver;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001895 mIsForegroundUid = isImportanceForeground(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001896 mActivityManager.getPackageImportance(mReceiver.mIdentity.mPackageName));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897
1898 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1899 if (records == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001900 records = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001901 mRecordsByProvider.put(provider, records);
1902 }
1903 if (!records.contains(this)) {
1904 records.add(this);
1905 }
David Christie2ff96af2014-01-30 16:09:37 -08001906
1907 // Update statistics for historical location requests by package/provider
1908 mRequestStatistics.startRequesting(
Wyatt Rileyf7075e02018-04-12 17:54:26 -07001909 mReceiver.mIdentity.mPackageName, provider, request.getInterval(),
1910 mIsForegroundUid);
1911 }
1912
1913 /**
1914 * Method to be called when record changes foreground/background
1915 */
1916 void updateForeground(boolean isForeground){
1917 mIsForegroundUid = isForeground;
1918 mRequestStatistics.updateForeground(
1919 mReceiver.mIdentity.mPackageName, mProvider, isForeground);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001920 }
1921
1922 /**
David Christie2ff96af2014-01-30 16:09:37 -08001923 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001924 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001925 void disposeLocked(boolean removeReceiver) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001926 mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
David Christie2ff96af2014-01-30 16:09:37 -08001927
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001928 // remove from mRecordsByProvider
1929 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1930 if (globalRecords != null) {
1931 globalRecords.remove(this);
1932 }
1933
1934 if (!removeReceiver) return; // the caller will handle the rest
1935
1936 // remove from Receiver#mUpdateRecords
1937 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1938 if (receiverRecords != null) {
1939 receiverRecords.remove(this.mProvider);
1940
1941 // and also remove the Receiver if it has no more update records
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001942 if (receiverRecords.size() == 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001943 removeUpdatesLocked(mReceiver);
1944 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001945 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001946 }
1947
1948 @Override
1949 public String toString() {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001950 return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
gomo48f1a642017-11-10 20:35:46 -08001951 + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground"
1952 : " background")
Wyatt Riley19adc022018-05-22 13:30:51 -07001953 + ")" + " " + mRealRequest + " "
1954 + mReceiver.mWorkSource + "]";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001955 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001956 }
1957
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001958 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07001959 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001960 IBinder binder = listener.asBinder();
1961 Receiver receiver = mReceivers.get(binder);
1962 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001963 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
1964 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001965 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001966 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001967 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001968 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001969 return null;
1970 }
Wen Jingcb3ab222014-03-27 13:42:59 +08001971 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001972 }
1973 return receiver;
1974 }
1975
David Christie82edc9b2013-07-19 11:31:42 -07001976 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07001977 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001978 Receiver receiver = mReceivers.get(intent);
1979 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001980 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
1981 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001982 mReceivers.put(intent, receiver);
1983 }
1984 return receiver;
1985 }
1986
Victoria Lease37425c32012-10-16 16:08:48 -07001987 /**
1988 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1989 * and consistency requirements.
1990 *
1991 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07001992 * @return a version of request that meets the given resolution and consistency requirements
1993 * @hide
1994 */
gomo48f1a642017-11-10 20:35:46 -08001995 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel,
1996 boolean callerHasLocationHardwarePermission) {
Victoria Lease37425c32012-10-16 16:08:48 -07001997 LocationRequest sanitizedRequest = new LocationRequest(request);
gomo48f1a642017-11-10 20:35:46 -08001998 if (!callerHasLocationHardwarePermission) {
1999 // allow setting low power mode only for callers with location hardware permission
2000 sanitizedRequest.setLowPowerMode(false);
2001 }
Victoria Lease37425c32012-10-16 16:08:48 -07002002 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
2003 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002004 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07002005 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07002006 break;
2007 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07002008 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07002009 break;
2010 }
2011 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07002012 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2013 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002014 }
Victoria Lease37425c32012-10-16 16:08:48 -07002015 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2016 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002017 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002018 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002019 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07002020 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002021 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002022 }
Victoria Lease37425c32012-10-16 16:08:48 -07002023 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002024 }
2025
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002026 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07002027 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002028 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002029 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002030 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07002031 String[] packages = mPackageManager.getPackagesForUid(uid);
2032 if (packages == null) {
2033 throw new SecurityException("invalid UID " + uid);
2034 }
2035 for (String pkg : packages) {
2036 if (packageName.equals(pkg)) return;
2037 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002038 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002039 }
2040
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002041 private void checkPendingIntent(PendingIntent intent) {
2042 if (intent == null) {
2043 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07002044 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002045 }
2046
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002047 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
David Christie40e57822013-07-30 11:36:48 -07002048 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002049 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002050 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002051 } else if (intent != null && listener != null) {
2052 throw new IllegalArgumentException("cannot register both listener and intent");
2053 } else if (intent != null) {
2054 checkPendingIntent(intent);
David Christie40e57822013-07-30 11:36:48 -07002055 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002056 } else {
David Christie40e57822013-07-30 11:36:48 -07002057 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002058 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07002059 }
2060
Nick Pellye0fd6932012-07-11 10:26:13 -07002061 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002062 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
2063 PendingIntent intent, String packageName) {
2064 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2065 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002066 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2067 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2068 request.getProvider());
David Christie82edc9b2013-07-19 11:31:42 -07002069 WorkSource workSource = request.getWorkSource();
Narayan Kamath32684dd2018-01-08 17:32:51 +00002070 if (workSource != null && !workSource.isEmpty()) {
David Christie40e57822013-07-30 11:36:48 -07002071 checkDeviceStatsAllowed();
2072 }
2073 boolean hideFromAppOps = request.getHideFromAppOps();
2074 if (hideFromAppOps) {
2075 checkUpdateAppOpsAllowed();
David Christie82edc9b2013-07-19 11:31:42 -07002076 }
gomo48f1a642017-11-10 20:35:46 -08002077 boolean callerHasLocationHardwarePermission =
2078 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
Maggieaa080f92018-01-04 15:35:11 -08002079 == PERMISSION_GRANTED;
gomo48f1a642017-11-10 20:35:46 -08002080 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
2081 callerHasLocationHardwarePermission);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002082
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002083 final int pid = Binder.getCallingPid();
2084 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002085 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002086 long identity = Binder.clearCallingIdentity();
2087 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002088 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
2089 // a location.
David Christieb870dbf2015-06-22 12:42:53 -07002090 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002091
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002092 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002093 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
David Christie40e57822013-07-30 11:36:48 -07002094 packageName, workSource, hideFromAppOps);
Victoria Lease37425c32012-10-16 16:08:48 -07002095 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04002096 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002097 } finally {
2098 Binder.restoreCallingIdentity(identity);
2099 }
2100 }
2101
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002102 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
2103 int pid, int uid, String packageName) {
2104 // Figure out the provider. Either its explicitly request (legacy use cases), or
2105 // use the fused provider
2106 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2107 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07002108 if (name == null) {
2109 throw new IllegalArgumentException("provider name must not be null");
2110 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07002111
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002112 LocationProviderInterface provider = mProvidersByName.get(name);
2113 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07002114 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002115 }
2116
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002117 UpdateRecord record = new UpdateRecord(name, request, receiver);
gomo48f1a642017-11-10 20:35:46 -08002118 if (D) {
2119 Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
2120 + " " + name + " " + request + " from " + packageName + "(" + uid + " "
2121 + (record.mIsForegroundUid ? "foreground" : "background")
2122 + (isThrottlingExemptLocked(receiver.mIdentity)
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002123 ? " [whitelisted]" : "") + ")");
gomo48f1a642017-11-10 20:35:46 -08002124 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002125
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002126 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
2127 if (oldRecord != null) {
2128 oldRecord.disposeLocked(false);
2129 }
2130
Maggie2a9409e2018-03-21 11:47:28 -07002131 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002132 if (isProviderEnabled) {
2133 applyRequirementsLocked(name);
2134 } else {
2135 // Notify the listener that updates are currently disabled
2136 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002137 }
David Christie0b837452013-07-29 16:02:13 -07002138 // Update the monitoring here just in case multiple location requests were added to the
2139 // same receiver (this request may be high power and the initial might not have been).
2140 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002141 }
2142
Nick Pellye0fd6932012-07-11 10:26:13 -07002143 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002144 public void removeUpdates(ILocationListener listener, PendingIntent intent,
2145 String packageName) {
2146 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002147
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002148 final int pid = Binder.getCallingPid();
2149 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002150
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002151 synchronized (mLock) {
David Christie82edc9b2013-07-19 11:31:42 -07002152 WorkSource workSource = null;
David Christie40e57822013-07-30 11:36:48 -07002153 boolean hideFromAppOps = false;
2154 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
2155 packageName, workSource, hideFromAppOps);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002156
2157 // providers may use public location API's, need to clear identity
2158 long identity = Binder.clearCallingIdentity();
2159 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002160 removeUpdatesLocked(receiver);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002161 } finally {
2162 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002163 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002164 }
2165 }
2166
2167 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08002168 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002169
2170 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
2171 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
2172 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07002173 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002174 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002175 }
2176
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07002177 receiver.updateMonitoring(false);
2178
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002179 // Record which providers were associated with this listener
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002180 HashSet<String> providers = new HashSet<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002181 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
2182 if (oldRecords != null) {
2183 // Call dispose() on the obsolete update records.
2184 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08002185 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002186 record.disposeLocked(false);
2187 }
2188 // Accumulate providers
2189 providers.addAll(oldRecords.keySet());
2190 }
2191
2192 // update provider
2193 for (String provider : providers) {
2194 // If provider is already disabled, don't need to do anything
Victoria Lease09eeaec2013-02-05 11:34:13 -08002195 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002196 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002197 }
2198
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002199 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002200 }
2201 }
2202
Dianne Hackbornc2293022013-02-06 23:14:49 -08002203 private void applyAllProviderRequirementsLocked() {
2204 for (LocationProviderInterface p : mProviders) {
2205 // If provider is already disabled, don't need to do anything
Dianne Hackborn64d41d72013-02-07 00:33:31 -08002206 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08002207 continue;
2208 }
2209
2210 applyRequirementsLocked(p.getName());
2211 }
2212 }
2213
Nick Pellye0fd6932012-07-11 10:26:13 -07002214 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07002215 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002216 if (D) Log.d(TAG, "getLastLocation: " + request);
2217 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002218 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07002219 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002220 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2221 request.getProvider());
2222 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07002223
David Christieb870dbf2015-06-22 12:42:53 -07002224 final int pid = Binder.getCallingPid();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002225 final int uid = Binder.getCallingUid();
2226 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07002227 try {
2228 if (mBlacklist.isBlacklisted(packageName)) {
gomo48f1a642017-11-10 20:35:46 -08002229 if (D) {
2230 Log.d(TAG, "not returning last loc for blacklisted app: " +
2231 packageName);
2232 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002233 return null;
2234 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002235
David Christieb870dbf2015-06-22 12:42:53 -07002236 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08002237 if (D) {
2238 Log.d(TAG, "not returning last loc for no op app: " +
2239 packageName);
2240 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002241 return null;
2242 }
2243
Victoria Leaseb711d572012-10-02 13:14:11 -07002244 synchronized (mLock) {
2245 // Figure out the provider. Either its explicitly request (deprecated API's),
2246 // or use the fused provider
2247 String name = request.getProvider();
2248 if (name == null) name = LocationManager.FUSED_PROVIDER;
2249 LocationProviderInterface provider = mProvidersByName.get(name);
2250 if (provider == null) return null;
2251
Maggie2a9409e2018-03-21 11:47:28 -07002252 if (!isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07002253
David Christie1b9b7b12013-04-15 15:31:11 -07002254 Location location;
2255 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2256 // Make sure that an app with coarse permissions can't get frequent location
2257 // updates by calling LocationManager.getLastKnownLocation repeatedly.
2258 location = mLastLocationCoarseInterval.get(name);
2259 } else {
2260 location = mLastLocation.get(name);
2261 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002262 if (location == null) {
2263 return null;
2264 }
Victoria Lease37425c32012-10-16 16:08:48 -07002265 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
gomo48f1a642017-11-10 20:35:46 -08002266 Location noGPSLocation = location.getExtraLocation(
2267 Location.EXTRA_NO_GPS_LOCATION);
Victoria Leaseb711d572012-10-02 13:14:11 -07002268 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08002269 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07002270 }
Victoria Lease37425c32012-10-16 16:08:48 -07002271 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08002272 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07002273 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002274 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002275 return null;
2276 } finally {
2277 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002278 }
2279 }
2280
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002281 /**
2282 * Provides an interface to inject and set the last location if location is not available
2283 * currently.
2284 *
2285 * This helps in cases where the product (Cars for example) has saved the last known location
2286 * before powering off. This interface lets the client inject the saved location while the GPS
2287 * chipset is getting its first fix, there by improving user experience.
2288 *
2289 * @param location - Location object to inject
2290 * @return true if update was successful, false if not
2291 */
2292 @Override
2293 public boolean injectLocation(Location location) {
2294 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
2295 "Location Hardware permission not granted to inject location");
2296 mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
2297 "Access Fine Location permission not granted to inject Location");
2298
2299 if (location == null) {
2300 if (D) {
2301 Log.d(TAG, "injectLocation(): called with null location");
2302 }
2303 return false;
2304 }
2305 LocationProviderInterface p = null;
2306 String provider = location.getProvider();
2307 if (provider != null) {
2308 p = mProvidersByName.get(provider);
2309 }
2310 if (p == null) {
2311 if (D) {
2312 Log.d(TAG, "injectLocation(): unknown provider");
2313 }
2314 return false;
2315 }
2316 synchronized (mLock) {
2317 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
2318 if (D) {
2319 Log.d(TAG, "Location disabled in Settings for current user:" + mCurrentUserId);
2320 }
2321 return false;
2322 } else {
2323 // NOTE: If last location is already available, location is not injected. If
2324 // provider's normal source (like a GPS chipset) have already provided an output,
2325 // there is no need to inject this location.
2326 if (mLastLocation.get(provider) == null) {
2327 updateLastLocationLocked(location, provider);
2328 } else {
2329 if (D) {
2330 Log.d(TAG, "injectLocation(): Location exists. Not updating");
2331 }
2332 return false;
2333 }
2334 }
2335 }
2336 return true;
2337 }
2338
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002339 @Override
2340 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
2341 String packageName) {
2342 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002343 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2344 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002345 checkPendingIntent(intent);
2346 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002347 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2348 request.getProvider());
gomo48f1a642017-11-10 20:35:46 -08002349 // Require that caller can manage given document
2350 boolean callerHasLocationHardwarePermission =
2351 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
Maggieaa080f92018-01-04 15:35:11 -08002352 == PERMISSION_GRANTED;
gomo48f1a642017-11-10 20:35:46 -08002353 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
2354 callerHasLocationHardwarePermission);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002355
Victoria Lease37425c32012-10-16 16:08:48 -07002356 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002357
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002358 // geo-fence manager uses the public location API, need to clear identity
2359 int uid = Binder.getCallingUid();
Xiaohui Chena4490622015-09-22 15:29:31 -07002360 // TODO: http://b/23822629
2361 if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
Victoria Lease56e675b2012-11-05 19:25:06 -08002362 // temporary measure until geofences work for secondary users
2363 Log.w(TAG, "proximity alerts are currently available only to the primary user");
2364 return;
2365 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002366 long identity = Binder.clearCallingIdentity();
2367 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002368 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
2369 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002370 } finally {
2371 Binder.restoreCallingIdentity(identity);
2372 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002373 }
2374
2375 @Override
2376 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002377 checkPendingIntent(intent);
2378 checkPackageName(packageName);
2379
2380 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
2381
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002382 // geo-fence manager uses the public location API, need to clear identity
2383 long identity = Binder.clearCallingIdentity();
2384 try {
2385 mGeofenceManager.removeFence(geofence, intent);
2386 } finally {
2387 Binder.restoreCallingIdentity(identity);
2388 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002389 }
2390
2391
2392 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002393 public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002394 if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09002395 return false;
2396 }
2397
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002398 try {
Lifu Tang30f95a72016-01-07 23:20:38 -08002399 mGnssStatusProvider.registerGnssStatusCallback(callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002400 } catch (RemoteException e) {
Lifu Tang30f95a72016-01-07 23:20:38 -08002401 Slog.e(TAG, "mGpsStatusProvider.registerGnssStatusCallback failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002402 return false;
2403 }
2404 return true;
2405 }
2406
Nick Pellye0fd6932012-07-11 10:26:13 -07002407 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002408 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002409 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002410 try {
Lifu Tang30f95a72016-01-07 23:20:38 -08002411 mGnssStatusProvider.unregisterGnssStatusCallback(callback);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002412 } catch (Exception e) {
Lifu Tang30f95a72016-01-07 23:20:38 -08002413 Slog.e(TAG, "mGpsStatusProvider.unregisterGnssStatusCallback failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002414 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002415 }
2416 }
2417
Nick Pellye0fd6932012-07-11 10:26:13 -07002418 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002419 public boolean addGnssMeasurementsListener(
gomo48f1a642017-11-10 20:35:46 -08002420 IGnssMeasurementsListener listener, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002421 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07002422 return false;
2423 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002424
2425 synchronized (mLock) {
2426 Identity callerIdentity
2427 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Wyatt Riley11cc7492018-01-17 08:48:27 -08002428 mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002429 long identity = Binder.clearCallingIdentity();
2430 try {
2431 if (isThrottlingExemptLocked(callerIdentity)
2432 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002433 mActivityManager.getPackageImportance(packageName))) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002434 return mGnssMeasurementsProvider.addListener(listener);
2435 }
2436 } finally {
2437 Binder.restoreCallingIdentity(identity);
2438 }
2439
2440 return true;
2441 }
destradaaea8a8a62014-06-23 18:19:03 -07002442 }
2443
2444 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002445 public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
2446 if (mGnssMeasurementsProvider != null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002447 synchronized (mLock) {
Wyatt Riley11cc7492018-01-17 08:48:27 -08002448 mGnssMeasurementsListeners.remove(listener.asBinder());
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002449 mGnssMeasurementsProvider.removeListener(listener);
2450 }
Wei Liu5241a4c2015-05-11 14:00:36 -07002451 }
destradaaea8a8a62014-06-23 18:19:03 -07002452 }
2453
2454 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002455 public boolean addGnssNavigationMessageListener(
2456 IGnssNavigationMessageListener listener,
destradaa4b3e3932014-07-21 18:01:47 -07002457 String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002458 if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07002459 return false;
2460 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002461
2462 synchronized (mLock) {
2463 Identity callerIdentity
gomo48f1a642017-11-10 20:35:46 -08002464 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Wyatt Riley11cc7492018-01-17 08:48:27 -08002465 mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002466 long identity = Binder.clearCallingIdentity();
2467 try {
2468 if (isThrottlingExemptLocked(callerIdentity)
2469 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002470 mActivityManager.getPackageImportance(packageName))) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002471 return mGnssNavigationMessageProvider.addListener(listener);
2472 }
2473 } finally {
2474 Binder.restoreCallingIdentity(identity);
2475 }
2476
2477 return true;
2478 }
destradaa4b3e3932014-07-21 18:01:47 -07002479 }
2480
2481 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002482 public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
2483 if (mGnssNavigationMessageProvider != null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002484 synchronized (mLock) {
Wyatt Riley11cc7492018-01-17 08:48:27 -08002485 mGnssNavigationMessageListeners.remove(listener.asBinder());
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002486 mGnssNavigationMessageProvider.removeListener(listener);
2487 }
Wei Liu5241a4c2015-05-11 14:00:36 -07002488 }
destradaa4b3e3932014-07-21 18:01:47 -07002489 }
2490
2491 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002492 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002493 if (provider == null) {
2494 // throw NullPointerException to remain compatible with previous implementation
2495 throw new NullPointerException();
2496 }
Victoria Lease37425c32012-10-16 16:08:48 -07002497 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2498 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002499
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002500 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04002501 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
Maggieaa080f92018-01-04 15:35:11 -08002502 != PERMISSION_GRANTED)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002503 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2504 }
2505
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002506 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002507 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002508 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07002509
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002510 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002511 }
2512 }
2513
Nick Pellye0fd6932012-07-11 10:26:13 -07002514 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002515 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07002516 if (Binder.getCallingUid() != Process.myUid()) {
2517 throw new SecurityException(
2518 "calling sendNiResponse from outside of the system is not allowed");
2519 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04002520 try {
2521 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002522 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002523 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04002524 return false;
2525 }
2526 }
2527
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002528 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002529 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11002530 * @throws SecurityException if the provider is not allowed to be
gomo48f1a642017-11-10 20:35:46 -08002531 * accessed by the caller
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002532 */
Nick Pellye0fd6932012-07-11 10:26:13 -07002533 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002534 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07002535 if (mProvidersByName.get(provider) == null) {
David Christie2ff96af2014-01-30 16:09:37 -08002536 return null;
Laurent Tub7f9d252012-10-16 14:25:00 -07002537 }
2538
Victoria Lease37425c32012-10-16 16:08:48 -07002539 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2540 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002541
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002542 LocationProviderInterface p;
2543 synchronized (mLock) {
2544 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002545 }
2546
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002547 if (p == null) return null;
2548 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002549 }
2550
Jason Monkb71218a2015-06-17 14:44:39 -04002551 /**
2552 * @return null if the provider does not exist
2553 * @throws SecurityException if the provider is not allowed to be
gomo48f1a642017-11-10 20:35:46 -08002554 * accessed by the caller
Jason Monkb71218a2015-06-17 14:44:39 -04002555 */
2556 @Override
2557 public String getNetworkProviderPackage() {
2558 LocationProviderInterface p;
2559 synchronized (mLock) {
2560 if (mProvidersByName.get(LocationManager.NETWORK_PROVIDER) == null) {
2561 return null;
2562 }
2563 p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
2564 }
2565
2566 if (p instanceof LocationProviderProxy) {
2567 return ((LocationProviderProxy) p).getConnectedPackageName();
2568 }
2569 return null;
2570 }
2571
Maggieaa080f92018-01-04 15:35:11 -08002572 /**
Maggie2a9409e2018-03-21 11:47:28 -07002573 * Returns the current location enabled/disabled status for a user
2574 *
2575 * @param userId the id of the user
2576 * @return true if location is enabled
2577 */
2578 @Override
2579 public boolean isLocationEnabledForUser(int userId) {
2580 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2581 checkInteractAcrossUsersPermission(userId);
2582
2583 long identity = Binder.clearCallingIdentity();
2584 try {
2585 synchronized (mLock) {
2586 final String allowedProviders = Settings.Secure.getStringForUser(
2587 mContext.getContentResolver(),
2588 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
2589 userId);
2590 if (allowedProviders == null) {
2591 return false;
2592 }
2593 final List<String> providerList = Arrays.asList(allowedProviders.split(","));
2594 for(String provider : mRealProviders.keySet()) {
2595 if (provider.equals(LocationManager.PASSIVE_PROVIDER)
2596 || provider.equals(LocationManager.FUSED_PROVIDER)) {
2597 continue;
2598 }
2599 if (providerList.contains(provider)) {
2600 return true;
2601 }
2602 }
2603 return false;
2604 }
2605 } finally {
2606 Binder.restoreCallingIdentity(identity);
2607 }
2608 }
2609
2610 /**
2611 * Enable or disable location for a user
2612 *
2613 * @param enabled true to enable location, false to disable location
2614 * @param userId the id of the user
2615 */
2616 @Override
2617 public void setLocationEnabledForUser(boolean enabled, int userId) {
2618 mContext.enforceCallingPermission(
2619 android.Manifest.permission.WRITE_SECURE_SETTINGS,
2620 "Requires WRITE_SECURE_SETTINGS permission");
2621
2622 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2623 checkInteractAcrossUsersPermission(userId);
2624
2625 long identity = Binder.clearCallingIdentity();
2626 try {
2627 synchronized (mLock) {
2628 final Set<String> allRealProviders = mRealProviders.keySet();
2629 // Update all providers on device plus gps and network provider when disabling
2630 // location
2631 Set<String> allProvidersSet = new ArraySet<>(allRealProviders.size() + 2);
2632 allProvidersSet.addAll(allRealProviders);
2633 // When disabling location, disable gps and network provider that could have been
2634 // enabled by location mode api.
2635 if (enabled == false) {
2636 allProvidersSet.add(LocationManager.GPS_PROVIDER);
2637 allProvidersSet.add(LocationManager.NETWORK_PROVIDER);
2638 }
2639 if (allProvidersSet.isEmpty()) {
2640 return;
2641 }
2642 // to ensure thread safety, we write the provider name with a '+' or '-'
2643 // and let the SettingsProvider handle it rather than reading and modifying
2644 // the list of enabled providers.
2645 final String prefix = enabled ? "+" : "-";
2646 StringBuilder locationProvidersAllowed = new StringBuilder();
2647 for (String provider : allProvidersSet) {
2648 if (provider.equals(LocationManager.PASSIVE_PROVIDER)
2649 || provider.equals(LocationManager.FUSED_PROVIDER)) {
2650 continue;
2651 }
2652 locationProvidersAllowed.append(prefix);
2653 locationProvidersAllowed.append(provider);
2654 locationProvidersAllowed.append(",");
2655 }
2656 // Remove the trailing comma
2657 locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
2658 Settings.Secure.putStringForUser(
2659 mContext.getContentResolver(),
2660 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
2661 locationProvidersAllowed.toString(),
2662 userId);
2663 }
2664 } finally {
2665 Binder.restoreCallingIdentity(identity);
2666 }
2667 }
2668
2669 /**
2670 * Returns the current enabled/disabled status of a location provider and user
2671 *
2672 * @param provider name of the provider
2673 * @param userId the id of the user
2674 * @return true if the provider exists and is enabled
2675 */
2676 @Override
2677 public boolean isProviderEnabledForUser(String provider, int userId) {
2678 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2679 checkInteractAcrossUsersPermission(userId);
2680
2681 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2682 // so we discourage its use
2683 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
2684
2685 int uid = Binder.getCallingUid();
2686 synchronized (mLock) {
2687 LocationProviderInterface p = mProvidersByName.get(provider);
2688 return p != null
2689 && isAllowedByUserSettingsLocked(provider, uid, userId);
2690 }
2691 }
2692
2693 /**
2694 * Enable or disable a single location provider.
2695 *
2696 * @param provider name of the provider
2697 * @param enabled true to enable the provider. False to disable the provider
2698 * @param userId the id of the user to set
2699 * @return true if the value was set, false on errors
2700 */
2701 @Override
2702 public boolean setProviderEnabledForUser(String provider, boolean enabled, int userId) {
2703 mContext.enforceCallingPermission(
2704 android.Manifest.permission.WRITE_SECURE_SETTINGS,
2705 "Requires WRITE_SECURE_SETTINGS permission");
2706
2707 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2708 checkInteractAcrossUsersPermission(userId);
2709
2710 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2711 // so we discourage its use
2712 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
2713
2714 long identity = Binder.clearCallingIdentity();
2715 try {
2716 synchronized (mLock) {
2717 // No such provider exists
2718 if (!mProvidersByName.containsKey(provider)) return false;
2719
2720 // If it is a test provider, do not write to Settings.Secure
2721 if (mMockProviders.containsKey(provider)) {
2722 setTestProviderEnabled(provider, enabled);
2723 return true;
2724 }
2725
2726 // to ensure thread safety, we write the provider name with a '+' or '-'
2727 // and let the SettingsProvider handle it rather than reading and modifying
2728 // the list of enabled providers.
2729 String providerChange = (enabled ? "+" : "-") + provider;
2730 return Settings.Secure.putStringForUser(
2731 mContext.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
2732 providerChange, userId);
2733 }
2734 } finally {
2735 Binder.restoreCallingIdentity(identity);
2736 }
2737 }
2738
2739 /**
Maggieaa080f92018-01-04 15:35:11 -08002740 * Read location provider status from Settings.Secure
2741 *
2742 * @param provider the location provider to query
2743 * @param userId the user id to query
2744 * @return true if the provider is enabled
2745 */
2746 private boolean isLocationProviderEnabledForUser(String provider, int userId) {
2747 long identity = Binder.clearCallingIdentity();
2748 try {
2749 // Use system settings
2750 ContentResolver cr = mContext.getContentResolver();
2751 String allowedProviders = Settings.Secure.getStringForUser(
2752 cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId);
2753 return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
2754 } finally {
2755 Binder.restoreCallingIdentity(identity);
2756 }
2757 }
2758
2759 /**
Maggie2a9409e2018-03-21 11:47:28 -07002760 * Method for checking INTERACT_ACROSS_USERS permission if specified user id is not the same as
2761 * current user id
2762 *
2763 * @param userId the user id to get or set value
2764 */
2765 private void checkInteractAcrossUsersPermission(int userId) {
2766 int uid = Binder.getCallingUid();
2767 if (UserHandle.getUserId(uid) != userId) {
2768 if (ActivityManager.checkComponentPermission(
2769 android.Manifest.permission.INTERACT_ACROSS_USERS, uid, -1, true)
2770 != PERMISSION_GRANTED) {
2771 throw new SecurityException("Requires INTERACT_ACROSS_USERS permission");
2772 }
2773 }
2774 }
2775
2776 /**
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002777 * Returns "true" if the UID belongs to a bound location provider.
2778 *
2779 * @param uid the uid
2780 * @return true if uid belongs to a bound location provider
2781 */
2782 private boolean isUidALocationProvider(int uid) {
2783 if (uid == Process.SYSTEM_UID) {
2784 return true;
2785 }
2786 if (mGeocodeProvider != null) {
David Christie1f141c12014-05-14 15:11:15 -07002787 if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002788 }
2789 for (LocationProviderProxy proxy : mProxyProviders) {
David Christie1f141c12014-05-14 15:11:15 -07002790 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002791 }
2792 return false;
2793 }
2794
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002795 private void checkCallerIsProvider() {
2796 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
Maggieaa080f92018-01-04 15:35:11 -08002797 == PERMISSION_GRANTED) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002798 return;
2799 }
2800
2801 // Previously we only used the INSTALL_LOCATION_PROVIDER
2802 // check. But that is system or signature
2803 // protection level which is not flexible enough for
2804 // providers installed oustide the system image. So
2805 // also allow providers with a UID matching the
2806 // currently bound package name
2807
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002808 if (isUidALocationProvider(Binder.getCallingUid())) {
2809 return;
2810 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002811
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002812 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2813 "or UID of a currently bound location provider");
2814 }
2815
David Christie1f141c12014-05-14 15:11:15 -07002816 /**
2817 * Returns true if the given package belongs to the given uid.
2818 */
2819 private boolean doesUidHavePackage(int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002820 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002821 return false;
2822 }
David Christie1f141c12014-05-14 15:11:15 -07002823 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2824 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002825 return false;
2826 }
David Christie1f141c12014-05-14 15:11:15 -07002827 for (String name : packageNames) {
2828 if (packageName.equals(name)) {
2829 return true;
2830 }
2831 }
2832 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002833 }
2834
Nick Pellye0fd6932012-07-11 10:26:13 -07002835 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05002836 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002837 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04002838
Nick Pelly2eeeec22012-07-18 13:13:37 -07002839 if (!location.isComplete()) {
2840 Log.w(TAG, "Dropping incomplete location: " + location);
2841 return;
2842 }
2843
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002844 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2845 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05002846 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002847 mLocationHandler.sendMessageAtFrontOfQueue(m);
2848 }
2849
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002850
Laurent Tu75defb62012-11-01 16:21:52 -07002851 private static boolean shouldBroadcastSafe(
2852 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002853 // Always broadcast the first update
2854 if (lastLoc == null) {
2855 return true;
2856 }
2857
Nick Pellyf1be6862012-05-15 10:53:42 -07002858 // Check whether sufficient time has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002859 long minTime = record.mRealRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002860 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2861 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002862 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002863 return false;
2864 }
2865
2866 // Check whether sufficient distance has been traveled
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002867 double minDistance = record.mRealRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002868 if (minDistance > 0.0) {
2869 if (loc.distanceTo(lastLoc) <= minDistance) {
2870 return false;
2871 }
2872 }
2873
Laurent Tu75defb62012-11-01 16:21:52 -07002874 // Check whether sufficient number of udpates is left
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002875 if (record.mRealRequest.getNumUpdates() <= 0) {
Laurent Tu75defb62012-11-01 16:21:52 -07002876 return false;
2877 }
2878
2879 // Check whether the expiry date has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002880 return record.mRealRequest.getExpireAt() >= now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002881 }
2882
Mike Lockwooda4903f22010-02-17 06:42:23 -05002883 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002884 if (D) Log.d(TAG, "incoming location: " + location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002885 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05002886 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
Laurent Tu60ec50a2012-10-04 17:00:10 -07002887 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002888 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002889 if (p == null) return;
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002890 updateLastLocationLocked(location, provider);
2891 // mLastLocation should have been updated from the updateLastLocationLocked call above.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002892 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002893 if (lastLocation == null) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002894 Log.e(TAG, "handleLocationChangedLocked() updateLastLocation failed");
2895 return;
Mike Lockwood4e50b782009-04-03 08:24:43 -07002896 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002897
David Christie1b9b7b12013-04-15 15:31:11 -07002898 // Update last known coarse interval location if enough time has passed.
2899 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2900 if (lastLocationCoarseInterval == null) {
2901 lastLocationCoarseInterval = new Location(location);
2902 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2903 }
2904 long timeDiffNanos = location.getElapsedRealtimeNanos()
2905 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2906 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
2907 lastLocationCoarseInterval.set(location);
2908 }
2909 // Don't ever return a coarse location that is more recent than the allowed update
2910 // interval (i.e. don't allow an app to keep registering and unregistering for
2911 // location updates to overcome the minimum interval).
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002912 Location noGPSLocation =
David Christie1b9b7b12013-04-15 15:31:11 -07002913 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2914
Laurent Tu60ec50a2012-10-04 17:00:10 -07002915 // Skip if there are no UpdateRecords for this provider.
2916 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2917 if (records == null || records.size() == 0) return;
2918
Victoria Lease09016ab2012-09-16 12:33:15 -07002919 // Fetch coarse location
2920 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07002921 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002922 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2923 }
2924
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002925 // Fetch latest status update time
2926 long newStatusUpdateTime = p.getStatusUpdateTime();
2927
David Christie2ff96af2014-01-30 16:09:37 -08002928 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002929 Bundle extras = new Bundle();
2930 int status = p.getStatus(extras);
2931
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002932 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002933 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07002934
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002935 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002936 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002937 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07002938 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07002939
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002940 int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
2941 if (!isCurrentProfile(receiverUserId)
2942 && !isUidALocationProvider(receiver.mIdentity.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07002943 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07002944 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07002945 " (current user: " + mCurrentUserId + ", app: " +
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002946 receiver.mIdentity.mPackageName + ")");
Victoria Leaseb711d572012-10-02 13:14:11 -07002947 }
2948 continue;
2949 }
2950
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002951 if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
gomo48f1a642017-11-10 20:35:46 -08002952 if (D) {
2953 Log.d(TAG, "skipping loc update for blacklisted app: " +
2954 receiver.mIdentity.mPackageName);
2955 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002956 continue;
2957 }
2958
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002959 if (!reportLocationAccessNoThrow(
2960 receiver.mIdentity.mPid,
2961 receiver.mIdentity.mUid,
2962 receiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002963 receiver.mAllowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08002964 if (D) {
2965 Log.d(TAG, "skipping loc update for no op app: " +
2966 receiver.mIdentity.mPackageName);
2967 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002968 continue;
2969 }
2970
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002971 Location notifyLocation;
Victoria Lease37425c32012-10-16 16:08:48 -07002972 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2973 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002974 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07002975 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002976 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002977 if (notifyLocation != null) {
2978 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07002979 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002980 if (lastLoc == null) {
2981 lastLoc = new Location(notifyLocation);
2982 r.mLastFixBroadcast = lastLoc;
2983 } else {
2984 lastLoc.set(notifyLocation);
2985 }
2986 if (!receiver.callLocationChangedLocked(notifyLocation)) {
2987 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2988 receiverDead = true;
2989 }
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002990 r.mRealRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002991 }
2992 }
2993
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002994 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002995 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07002996 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002997
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002998 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002999 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07003000 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08003001 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07003002 }
3003 }
3004
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003005 // track expired records
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003006 if (r.mRealRequest.getNumUpdates() <= 0 || r.mRealRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003007 if (deadUpdateRecords == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003008 deadUpdateRecords = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003009 }
3010 deadUpdateRecords.add(r);
3011 }
3012 // track dead receivers
3013 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07003014 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003015 deadReceivers = new ArrayList<>();
Mike Lockwood03ca2162010-04-01 08:10:09 -07003016 }
3017 if (!deadReceivers.contains(receiver)) {
3018 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003019 }
3020 }
3021 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003022
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003023 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003024 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003025 for (Receiver receiver : deadReceivers) {
3026 removeUpdatesLocked(receiver);
3027 }
3028 }
3029 if (deadUpdateRecords != null) {
3030 for (UpdateRecord r : deadUpdateRecords) {
3031 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003032 }
Victoria Lease8b38b292012-12-04 15:04:43 -08003033 applyRequirementsLocked(provider);
3034 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003035 }
3036
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003037 /**
3038 * Updates last location with the given location
3039 *
3040 * @param location new location to update
3041 * @param provider Location provider to update for
3042 */
3043 private void updateLastLocationLocked(Location location, String provider) {
3044 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3045 Location lastNoGPSLocation;
3046 Location lastLocation = mLastLocation.get(provider);
3047 if (lastLocation == null) {
3048 lastLocation = new Location(provider);
3049 mLastLocation.put(provider, lastLocation);
3050 } else {
3051 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3052 if (noGPSLocation == null && lastNoGPSLocation != null) {
3053 // New location has no no-GPS location: adopt last no-GPS location. This is set
3054 // directly into location because we do not want to notify COARSE clients.
3055 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
3056 }
3057 }
3058 lastLocation.set(location);
3059 }
3060
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003061 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08003062 public LocationWorkerHandler(Looper looper) {
3063 super(looper, null, true);
3064 }
3065
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003066 @Override
3067 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003068 switch (msg.what) {
3069 case MSG_LOCATION_CHANGED:
3070 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
3071 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003072 }
3073 }
3074 }
3075
Victoria Lease54ca7ae2013-01-08 09:39:50 -08003076 private boolean isMockProvider(String provider) {
3077 synchronized (mLock) {
3078 return mMockProviders.containsKey(provider);
3079 }
3080 }
3081
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003082 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08003083 // create a working copy of the incoming Location so that the service can modify it without
3084 // disturbing the caller's copy
3085 Location myLocation = new Location(location);
3086 String provider = myLocation.getProvider();
3087
3088 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
3089 // bit if location did not come from a mock provider because passive/fused providers can
3090 // forward locations from mock providers, and should not grant them legitimacy in doing so.
3091 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
3092 myLocation.setIsFromMockProvider(true);
3093 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08003094
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003095 synchronized (mLock) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08003096 if (isAllowedByCurrentUserSettingsLocked(provider)) {
3097 if (!passive) {
3098 // notify passive provider of the new location
3099 mPassiveProvider.updateLocation(myLocation);
3100 }
Victoria Lease54ca7ae2013-01-08 09:39:50 -08003101 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003102 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003103 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003104 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003105
Mike Lockwoode97ae402010-09-29 15:23:46 -04003106 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
3107 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003108 public void onPackageDisappeared(String packageName, int reason) {
3109 // remove all receivers associated with this package name
3110 synchronized (mLock) {
3111 ArrayList<Receiver> deadReceivers = null;
3112
3113 for (Receiver receiver : mReceivers.values()) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003114 if (receiver.mIdentity.mPackageName.equals(packageName)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003115 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003116 deadReceivers = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003117 }
3118 deadReceivers.add(receiver);
3119 }
3120 }
3121
3122 // perform removal outside of mReceivers loop
3123 if (deadReceivers != null) {
3124 for (Receiver receiver : deadReceivers) {
3125 removeUpdatesLocked(receiver);
3126 }
3127 }
3128 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003129 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04003130 };
3131
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003132 // Geocoder
3133
Nick Pellye0fd6932012-07-11 10:26:13 -07003134 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04003135 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07003136 return mGeocodeProvider != null;
3137 }
3138
Nick Pellye0fd6932012-07-11 10:26:13 -07003139 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003140 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003141 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003142 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003143 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
3144 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003145 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003146 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003147 }
3148
Mike Lockwooda55c3212009-04-15 11:10:11 -04003149
Nick Pellye0fd6932012-07-11 10:26:13 -07003150 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003151 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04003152 double lowerLeftLatitude, double lowerLeftLongitude,
3153 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003154 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003155
3156 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003157 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
3158 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
3159 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003160 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003161 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003162 }
3163
3164 // Mock Providers
3165
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003166 private boolean canCallerAccessMockLocation(String opPackageName) {
3167 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
3168 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003169 }
3170
Nick Pellye0fd6932012-07-11 10:26:13 -07003171 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003172 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
3173 if (!canCallerAccessMockLocation(opPackageName)) {
3174 return;
3175 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003176
Mike Lockwooda4903f22010-02-17 06:42:23 -05003177 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
3178 throw new IllegalArgumentException("Cannot mock the passive location provider");
3179 }
3180
Mike Lockwood86328a92009-10-23 08:38:25 -04003181 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003182 synchronized (mLock) {
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003183 // remove the real provider if we are replacing GPS or network provider
3184 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07003185 || LocationManager.NETWORK_PROVIDER.equals(name)
3186 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05003187 LocationProviderInterface p = mProvidersByName.get(name);
3188 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003189 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003190 }
3191 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003192 addTestProviderLocked(name, properties);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003193 updateProvidersLocked();
3194 }
Mike Lockwood86328a92009-10-23 08:38:25 -04003195 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003196 }
3197
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003198 private void addTestProviderLocked(String name, ProviderProperties properties) {
3199 if (mProvidersByName.get(name) != null) {
3200 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
3201 }
3202 MockProvider provider = new MockProvider(name, this, properties);
3203 addProviderLocked(provider);
3204 mMockProviders.put(name, provider);
3205 mLastLocation.put(name, null);
3206 mLastLocationCoarseInterval.put(name, null);
3207 }
3208
Nick Pellye0fd6932012-07-11 10:26:13 -07003209 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003210 public void removeTestProvider(String provider, String opPackageName) {
3211 if (!canCallerAccessMockLocation(opPackageName)) {
3212 return;
3213 }
3214
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003215 synchronized (mLock) {
Tom O'Neill07ee5d12014-03-03 17:48:35 -08003216
3217 // These methods can't be called after removing the test provider, so first make sure
Tom O'Neillfe6d3c52014-03-04 08:26:17 -08003218 // we don't leave anything dangling.
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003219 clearTestProviderEnabled(provider, opPackageName);
3220 clearTestProviderLocation(provider, opPackageName);
3221 clearTestProviderStatus(provider, opPackageName);
Tom O'Neill07ee5d12014-03-03 17:48:35 -08003222
You Kima6d0b6f2012-10-28 03:58:44 +09003223 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003224 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003225 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3226 }
Mike Lockwood86328a92009-10-23 08:38:25 -04003227 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003228 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003229
3230 // reinstate real provider if available
3231 LocationProviderInterface realProvider = mRealProviders.get(provider);
3232 if (realProvider != null) {
3233 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003234 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003235 mLastLocation.put(provider, null);
David Christie1b9b7b12013-04-15 15:31:11 -07003236 mLastLocationCoarseInterval.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003237 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04003238 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003239 }
3240 }
3241
Nick Pellye0fd6932012-07-11 10:26:13 -07003242 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003243 public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
3244 if (!canCallerAccessMockLocation(opPackageName)) {
3245 return;
3246 }
3247
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003248 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003249 MockProvider mockProvider = mMockProviders.get(provider);
3250 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003251 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3252 }
Tom O'Neilla206a0f2016-12-15 10:26:28 -08003253
3254 // Ensure that the location is marked as being mock. There's some logic to do this in
3255 // handleLocationChanged(), but it fails if loc has the wrong provider (bug 33091107).
3256 Location mock = new Location(loc);
3257 mock.setIsFromMockProvider(true);
3258
3259 if (!TextUtils.isEmpty(loc.getProvider()) && !provider.equals(loc.getProvider())) {
3260 // The location has an explicit provider that is different from the mock provider
3261 // name. The caller may be trying to fool us via bug 33091107.
3262 EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
3263 provider + "!=" + loc.getProvider());
3264 }
3265
Mike Lockwood95427cd2009-05-07 13:27:54 -04003266 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
3267 long identity = Binder.clearCallingIdentity();
Tom O'Neilla206a0f2016-12-15 10:26:28 -08003268 mockProvider.setLocation(mock);
Mike Lockwood95427cd2009-05-07 13:27:54 -04003269 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003270 }
3271 }
3272
Nick Pellye0fd6932012-07-11 10:26:13 -07003273 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003274 public void clearTestProviderLocation(String provider, String opPackageName) {
3275 if (!canCallerAccessMockLocation(opPackageName)) {
3276 return;
3277 }
3278
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003279 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003280 MockProvider mockProvider = mMockProviders.get(provider);
3281 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003282 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3283 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003284 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003285 }
3286 }
3287
Nick Pellye0fd6932012-07-11 10:26:13 -07003288 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003289 public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
3290 if (!canCallerAccessMockLocation(opPackageName)) {
3291 return;
3292 }
Maggie2a9409e2018-03-21 11:47:28 -07003293 setTestProviderEnabled(provider, enabled);
3294 }
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003295
Maggie2a9409e2018-03-21 11:47:28 -07003296 /** Enable or disable a test location provider. */
3297 private void setTestProviderEnabled(String provider, boolean enabled) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003298 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003299 MockProvider mockProvider = mMockProviders.get(provider);
3300 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003301 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3302 }
Mike Lockwood86328a92009-10-23 08:38:25 -04003303 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003304 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003305 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003306 mEnabledProviders.add(provider);
3307 mDisabledProviders.remove(provider);
3308 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003309 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003310 mEnabledProviders.remove(provider);
3311 mDisabledProviders.add(provider);
3312 }
3313 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04003314 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003315 }
3316 }
3317
Nick Pellye0fd6932012-07-11 10:26:13 -07003318 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003319 public void clearTestProviderEnabled(String provider, String opPackageName) {
3320 if (!canCallerAccessMockLocation(opPackageName)) {
3321 return;
3322 }
3323
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003324 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003325 MockProvider mockProvider = mMockProviders.get(provider);
3326 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003327 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3328 }
Mike Lockwood86328a92009-10-23 08:38:25 -04003329 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003330 mEnabledProviders.remove(provider);
3331 mDisabledProviders.remove(provider);
3332 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04003333 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003334 }
3335 }
3336
Nick Pellye0fd6932012-07-11 10:26:13 -07003337 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003338 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
3339 String opPackageName) {
3340 if (!canCallerAccessMockLocation(opPackageName)) {
3341 return;
3342 }
3343
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003344 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003345 MockProvider mockProvider = mMockProviders.get(provider);
3346 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003347 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3348 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003349 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003350 }
3351 }
3352
Nick Pellye0fd6932012-07-11 10:26:13 -07003353 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003354 public void clearTestProviderStatus(String provider, String opPackageName) {
3355 if (!canCallerAccessMockLocation(opPackageName)) {
3356 return;
3357 }
3358
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003359 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003360 MockProvider mockProvider = mMockProviders.get(provider);
3361 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003362 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3363 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003364 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003365 }
3366 }
3367
3368 private void log(String log) {
3369 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003370 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003371 }
3372 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003373
3374 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003375 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06003376 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Nick Pellye0fd6932012-07-11 10:26:13 -07003377
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003378 synchronized (mLock) {
Siddharth Raybb608c82017-03-16 11:33:34 -07003379 if (args.length > 0 && args[0].equals("--gnssmetrics")) {
3380 if (mGnssMetricsProvider != null) {
3381 pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
3382 }
3383 return;
3384 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003385 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003386 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003387 for (Receiver receiver : mReceivers.values()) {
3388 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003389 }
David Christie2ff96af2014-01-30 16:09:37 -08003390 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003391 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
3392 pw.println(" " + entry.getKey() + ":");
3393 for (UpdateRecord record : entry.getValue()) {
3394 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003395 }
3396 }
Wyatt Riley11cc7492018-01-17 08:48:27 -08003397 pw.println(" Active GnssMeasurement Listeners:");
3398 for (Identity identity : mGnssMeasurementsListeners.values()) {
3399 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3400 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3401 }
3402 pw.println(" Active GnssNavigationMessage Listeners:");
3403 for (Identity identity : mGnssNavigationMessageListeners.values()) {
3404 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3405 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3406 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003407 pw.println(" Overlay Provider Packages:");
3408 for (LocationProviderInterface provider : mProviders) {
3409 if (provider instanceof LocationProviderProxy) {
3410 pw.println(" " + provider.getName() + ": "
3411 + ((LocationProviderProxy) provider).getConnectedPackageName());
3412 }
3413 }
David Christie2ff96af2014-01-30 16:09:37 -08003414 pw.println(" Historical Records by Provider:");
3415 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
3416 : mRequestStatistics.statistics.entrySet()) {
3417 PackageProviderKey key = entry.getKey();
3418 PackageStatistics stats = entry.getValue();
3419 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
3420 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003421 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003422 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
3423 String provider = entry.getKey();
3424 Location location = entry.getValue();
3425 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003426 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003427
David Christie1b9b7b12013-04-15 15:31:11 -07003428 pw.println(" Last Known Locations Coarse Intervals:");
3429 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
3430 String provider = entry.getKey();
3431 Location location = entry.getValue();
3432 pw.println(" " + provider + ": " + location);
3433 }
3434
Nick Pellye0fd6932012-07-11 10:26:13 -07003435 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003436
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003437 if (mEnabledProviders.size() > 0) {
3438 pw.println(" Enabled Providers:");
3439 for (String i : mEnabledProviders) {
3440 pw.println(" " + i);
3441 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003442
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003443 }
3444 if (mDisabledProviders.size() > 0) {
3445 pw.println(" Disabled Providers:");
3446 for (String i : mDisabledProviders) {
3447 pw.println(" " + i);
3448 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003449 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07003450 pw.append(" ");
3451 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003452 if (mMockProviders.size() > 0) {
3453 pw.println(" Mock Providers:");
3454 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003455 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003456 }
3457 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003458
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08003459 if (!mBackgroundThrottlePackageWhitelist.isEmpty()) {
3460 pw.println(" Throttling Whitelisted Packages:");
3461 for (String packageName : mBackgroundThrottlePackageWhitelist) {
3462 pw.println(" " + packageName);
3463 }
3464 }
3465
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003466 pw.append(" fudger: ");
gomo48f1a642017-11-10 20:35:46 -08003467 mLocationFudger.dump(fd, pw, args);
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003468
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003469 if (args.length > 0 && "short".equals(args[0])) {
3470 return;
3471 }
gomo48f1a642017-11-10 20:35:46 -08003472 for (LocationProviderInterface provider : mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003473 pw.print(provider.getName() + " Internal State");
3474 if (provider instanceof LocationProviderProxy) {
3475 LocationProviderProxy proxy = (LocationProviderProxy) provider;
3476 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003477 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003478 pw.println(":");
3479 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003480 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08003481 if (mGnssBatchingInProgress) {
3482 pw.println(" GNSS batching in progress");
3483 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003484 }
3485 }
3486}