blob: bea414f69f43da442c3e057e4789704c8af5ed9a [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 }
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700428 record.mIsForegroundUid = foreground;
429
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,
Victoria Lease37425c32012-10-16 16:08:48 -0700964 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700965 // call this after broadcasting so we do not increment
966 // if we throw an exeption.
967 incrementPendingBroadcastsLocked();
968 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 } catch (PendingIntent.CanceledException e) {
970 return false;
971 }
972 }
973 return true;
974 }
975
976 public boolean callLocationChangedLocked(Location location) {
977 if (mListener != null) {
978 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700979 synchronized (this) {
980 // synchronize to ensure incrementPendingBroadcastsLocked()
981 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800982 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700983 // call this after broadcasting so we do not increment
984 // if we throw an exeption.
985 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700986 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 } catch (RemoteException e) {
988 return false;
989 }
990 } else {
991 Intent locationChanged = new Intent();
gomo48f1a642017-11-10 20:35:46 -0800992 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED,
993 new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700995 synchronized (this) {
996 // synchronize to ensure incrementPendingBroadcastsLocked()
997 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700998 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700999 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -07001000 // call this after broadcasting so we do not increment
1001 // if we throw an exeption.
1002 incrementPendingBroadcastsLocked();
1003 }
1004 } catch (PendingIntent.CanceledException e) {
1005 return false;
1006 }
1007 }
1008 return true;
1009 }
1010
1011 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -07001012 // First update AppOp monitoring.
1013 // An app may get/lose location access as providers are enabled/disabled.
1014 updateMonitoring(true);
1015
Mike Lockwood48f17512009-04-23 09:12:08 -07001016 if (mListener != null) {
1017 try {
1018 synchronized (this) {
1019 // synchronize to ensure incrementPendingBroadcastsLocked()
1020 // is called before decrementPendingBroadcasts()
1021 if (enabled) {
1022 mListener.onProviderEnabled(provider);
1023 } else {
1024 mListener.onProviderDisabled(provider);
1025 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001026 // call this after broadcasting so we do not increment
1027 // if we throw an exeption.
1028 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001029 }
1030 } catch (RemoteException e) {
1031 return false;
1032 }
1033 } else {
1034 Intent providerIntent = new Intent();
1035 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
1036 try {
1037 synchronized (this) {
1038 // synchronize to ensure incrementPendingBroadcastsLocked()
1039 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001040 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -07001041 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -07001042 // call this after broadcasting so we do not increment
1043 // if we throw an exeption.
1044 incrementPendingBroadcastsLocked();
1045 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 } catch (PendingIntent.CanceledException e) {
1047 return false;
1048 }
1049 }
1050 return true;
1051 }
1052
Nick Pellyf1be6862012-05-15 10:53:42 -07001053 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001055 if (D) Log.d(TAG, "Location listener died");
1056
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001057 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001058 removeUpdatesLocked(this);
1059 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001060 synchronized (this) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001061 clearPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001062 }
1063 }
1064
Nick Pellye0fd6932012-07-11 10:26:13 -07001065 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001066 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1067 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001068 synchronized (this) {
1069 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001070 }
1071 }
1072
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001073 // this must be called while synchronized by caller in a synchronized block
1074 // containing the sending of the broadcaset
1075 private void incrementPendingBroadcastsLocked() {
1076 if (mPendingBroadcasts++ == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001077 mWakeLock.acquire();
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001078 }
1079 }
1080
1081 private void decrementPendingBroadcastsLocked() {
1082 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001083 if (mWakeLock.isHeld()) {
1084 mWakeLock.release();
1085 }
1086 }
1087 }
1088
1089 public void clearPendingBroadcastsLocked() {
1090 if (mPendingBroadcasts > 0) {
1091 mPendingBroadcasts = 0;
1092 if (mWakeLock.isHeld()) {
1093 mWakeLock.release();
1094 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001095 }
1096 }
1097 }
1098
Nick Pellye0fd6932012-07-11 10:26:13 -07001099 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001100 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001101 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -04001102 //the receiver list if it is not found. If it is not found then the
1103 //LocationListener was removed when it had a pending broadcast and should
1104 //not be added back.
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001105 synchronized (mLock) {
1106 IBinder binder = listener.asBinder();
1107 Receiver receiver = mReceivers.get(binder);
1108 if (receiver != null) {
1109 synchronized (receiver) {
1110 // so wakelock calls will succeed
1111 long identity = Binder.clearCallingIdentity();
1112 receiver.decrementPendingBroadcastsLocked();
1113 Binder.restoreCallingIdentity(identity);
David Christie2ff96af2014-01-30 16:09:37 -08001114 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001115 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 }
1117 }
1118
Lifu Tang82f893d2016-01-21 18:15:33 -08001119 /**
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001120 * Returns the year of the GNSS hardware.
Lifu Tang82f893d2016-01-21 18:15:33 -08001121 */
1122 @Override
Lifu Tang9363b942016-02-16 18:07:00 -08001123 public int getGnssYearOfHardware() {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001124 if (mGnssSystemInfoProvider != null) {
Lifu Tang9363b942016-02-16 18:07:00 -08001125 return mGnssSystemInfoProvider.getGnssYearOfHardware();
Lifu Tang82f893d2016-01-21 18:15:33 -08001126 } else {
1127 return 0;
1128 }
1129 }
1130
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001131
1132 /**
1133 * Returns the model name of the GNSS hardware.
1134 */
1135 @Override
Wyatt Riley49097c02018-03-15 09:14:43 -07001136 @Nullable
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001137 public String getGnssHardwareModelName() {
1138 if (mGnssSystemInfoProvider != null) {
1139 return mGnssSystemInfoProvider.getGnssHardwareModelName();
1140 } else {
Wyatt Riley49097c02018-03-15 09:14:43 -07001141 return null;
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001142 }
1143 }
1144
Wyatt Rileycf879db2017-01-12 13:57:38 -08001145 /**
1146 * Runs some checks for GNSS (FINE) level permissions, used by several methods which directly
1147 * (try to) access GNSS information at this layer.
1148 */
1149 private boolean hasGnssPermissions(String packageName) {
1150 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1151 checkResolutionLevelIsSufficientForProviderUse(
1152 allowedResolutionLevel,
1153 LocationManager.GPS_PROVIDER);
1154
1155 int pid = Binder.getCallingPid();
1156 int uid = Binder.getCallingUid();
1157 long identity = Binder.clearCallingIdentity();
1158 boolean hasLocationAccess;
1159 try {
1160 hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1161 } finally {
1162 Binder.restoreCallingIdentity(identity);
1163 }
1164
1165 return hasLocationAccess;
1166 }
1167
1168 /**
1169 * Returns the GNSS batching size, if available.
1170 */
1171 @Override
1172 public int getGnssBatchSize(String packageName) {
1173 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1174 "Location Hardware permission not granted to access hardware batching");
1175
1176 if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
Yu-Han Yang3557cc72018-03-21 12:48:36 -07001177 return mGnssBatchingProvider.getBatchSize();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001178 } else {
1179 return 0;
1180 }
1181 }
1182
1183 /**
1184 * Adds a callback for GNSS Batching events, if permissions allow, which are transported
1185 * to potentially multiple listeners by the BatchedLocationCallbackTransport above this.
1186 */
1187 @Override
1188 public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
1189 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1190 "Location Hardware permission not granted to access hardware batching");
1191
1192 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1193 return false;
1194 }
1195
1196 mGnssBatchingCallback = callback;
1197 mGnssBatchingDeathCallback = new LinkedCallback(callback);
1198 try {
1199 callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
1200 } catch (RemoteException e) {
1201 // if the remote process registering the listener is already dead, just swallow the
1202 // exception and return
1203 Log.e(TAG, "Remote listener already died.", e);
1204 return false;
1205 }
1206
1207 return true;
1208 }
1209
1210 private class LinkedCallback implements IBinder.DeathRecipient {
1211 private final IBatchedLocationCallback mCallback;
1212
1213 public LinkedCallback(@NonNull IBatchedLocationCallback callback) {
1214 mCallback = callback;
1215 }
1216
1217 @NonNull
1218 public IBatchedLocationCallback getUnderlyingListener() {
1219 return mCallback;
1220 }
1221
1222 @Override
1223 public void binderDied() {
1224 Log.d(TAG, "Remote Batching Callback died: " + mCallback);
1225 stopGnssBatch();
1226 removeGnssBatchingCallback();
1227 }
1228 }
1229
1230 /**
1231 * Removes callback for GNSS batching
1232 */
1233 @Override
1234 public void removeGnssBatchingCallback() {
1235 try {
1236 mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
1237 0 /* flags */);
1238 } catch (NoSuchElementException e) {
1239 // if the death callback isn't connected (it should be...), log error, swallow the
1240 // exception and return
1241 Log.e(TAG, "Couldn't unlink death callback.", e);
1242 }
1243 mGnssBatchingCallback = null;
1244 mGnssBatchingDeathCallback = null;
1245 }
1246
1247
1248 /**
1249 * Starts GNSS batching, if available.
1250 */
1251 @Override
1252 public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
1253 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1254 "Location Hardware permission not granted to access hardware batching");
1255
1256 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1257 return false;
1258 }
1259
1260 if (mGnssBatchingInProgress) {
1261 // Current design does not expect multiple starts to be called repeatedly
1262 Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
1263 // Try to clean up anyway, and continue
1264 stopGnssBatch();
1265 }
1266
1267 mGnssBatchingInProgress = true;
1268 return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
1269 }
1270
1271 /**
1272 * Flushes a GNSS batch in progress
1273 */
1274 @Override
1275 public void flushGnssBatch(String packageName) {
1276 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1277 "Location Hardware permission not granted to access hardware batching");
1278
1279 if (!hasGnssPermissions(packageName)) {
1280 Log.e(TAG, "flushGnssBatch called without GNSS permissions");
1281 return;
1282 }
1283
1284 if (!mGnssBatchingInProgress) {
1285 Log.w(TAG, "flushGnssBatch called with no batch in progress");
1286 }
1287
1288 if (mGnssBatchingProvider != null) {
gomo48f1a642017-11-10 20:35:46 -08001289 mGnssBatchingProvider.flush();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001290 }
1291 }
1292
1293 /**
1294 * Stops GNSS batching
1295 */
1296 @Override
1297 public boolean stopGnssBatch() {
1298 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1299 "Location Hardware permission not granted to access hardware batching");
1300
1301 if (mGnssBatchingProvider != null) {
1302 mGnssBatchingInProgress = false;
1303 return mGnssBatchingProvider.stop();
gomo48f1a642017-11-10 20:35:46 -08001304 } else {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001305 return false;
1306 }
1307 }
1308
1309 @Override
1310 public void reportLocationBatch(List<Location> locations) {
1311 checkCallerIsProvider();
1312
1313 // Currently used only for GNSS locations - update permissions check if changed
1314 if (isAllowedByCurrentUserSettingsLocked(LocationManager.GPS_PROVIDER)) {
1315 if (mGnssBatchingCallback == null) {
1316 Slog.e(TAG, "reportLocationBatch() called without active Callback");
1317 return;
1318 }
1319 try {
1320 mGnssBatchingCallback.onLocationBatch(locations);
1321 } catch (RemoteException e) {
1322 Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
1323 }
1324 } else {
1325 Slog.w(TAG, "reportLocationBatch() called without user permission, locations blocked");
1326 }
1327 }
1328
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001329 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001330 mProviders.add(provider);
1331 mProvidersByName.put(provider.getName(), provider);
1332 }
1333
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001334 private void removeProviderLocked(LocationProviderInterface provider) {
1335 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001336 mProviders.remove(provider);
1337 mProvidersByName.remove(provider.getName());
1338 }
1339
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001340 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -08001341 * Returns "true" if access to the specified location provider is allowed by the current
1342 * user's settings. Access to all location providers is forbidden to non-location-provider
1343 * processes belonging to background users.
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001344 *
1345 * @param provider the name of the location provider
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001346 */
Victoria Lease09eeaec2013-02-05 11:34:13 -08001347 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
Maggie2a9409e2018-03-21 11:47:28 -07001348 return isAllowedByUserSettingsLockedForUser(provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001349 }
1350
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001351 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -08001352 * Returns "true" if access to the specified location provider is allowed by the specified
1353 * user's settings. Access to all location providers is forbidden to non-location-provider
1354 * processes belonging to background users.
1355 *
1356 * @param provider the name of the location provider
Maggie2a9409e2018-03-21 11:47:28 -07001357 * @param userId the user id to query
Victoria Lease09eeaec2013-02-05 11:34:13 -08001358 */
Maggie2a9409e2018-03-21 11:47:28 -07001359 private boolean isAllowedByUserSettingsLockedForUser(String provider, int userId) {
1360 if (mEnabledProviders.contains(provider)) {
1361 return true;
1362 }
1363 if (mDisabledProviders.contains(provider)) {
1364 return false;
1365 }
1366 return isLocationProviderEnabledForUser(provider, userId);
1367 }
1368
1369
1370 /**
1371 * Returns "true" if access to the specified location provider is allowed by the specified
1372 * user's settings. Access to all location providers is forbidden to non-location-provider
1373 * processes belonging to background users.
1374 *
1375 * @param provider the name of the location provider
1376 * @param uid the requestor's UID
1377 * @param userId the user id to query
1378 */
1379 private boolean isAllowedByUserSettingsLocked(String provider, int uid, int userId) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001380 if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001381 return false;
1382 }
Maggie2a9409e2018-03-21 11:47:28 -07001383 return isAllowedByUserSettingsLockedForUser(provider, userId);
Victoria Lease09eeaec2013-02-05 11:34:13 -08001384 }
1385
1386 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001387 * Returns the permission string associated with the specified resolution level.
1388 *
1389 * @param resolutionLevel the resolution level
1390 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001391 */
Victoria Lease37425c32012-10-16 16:08:48 -07001392 private String getResolutionPermission(int resolutionLevel) {
1393 switch (resolutionLevel) {
1394 case RESOLUTION_LEVEL_FINE:
1395 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1396 case RESOLUTION_LEVEL_COARSE:
1397 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1398 default:
1399 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001400 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001401 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001402
Victoria Leaseda479c52012-10-15 15:24:16 -07001403 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001404 * Returns the resolution level allowed to the given PID/UID pair.
1405 *
1406 * @param pid the PID
1407 * @param uid the UID
1408 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -07001409 */
Victoria Lease37425c32012-10-16 16:08:48 -07001410 private int getAllowedResolutionLevel(int pid, int uid) {
1411 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001412 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001413 return RESOLUTION_LEVEL_FINE;
1414 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001415 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001416 return RESOLUTION_LEVEL_COARSE;
1417 } else {
1418 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001419 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001420 }
1421
1422 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001423 * Returns the resolution level allowed to the caller
1424 *
1425 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -07001426 */
Victoria Lease37425c32012-10-16 16:08:48 -07001427 private int getCallerAllowedResolutionLevel() {
1428 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1429 }
1430
1431 /**
1432 * Throw SecurityException if specified resolution level is insufficient to use geofences.
1433 *
1434 * @param allowedResolutionLevel resolution level allowed to caller
1435 */
1436 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1437 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001438 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1439 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440 }
1441
Victoria Lease37425c32012-10-16 16:08:48 -07001442 /**
1443 * Return the minimum resolution level required to use the specified location provider.
1444 *
1445 * @param provider the name of the location provider
1446 * @return minimum resolution level required for provider
1447 */
1448 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001449 if (LocationManager.GPS_PROVIDER.equals(provider) ||
1450 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1451 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001452 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -07001453 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1454 LocationManager.FUSED_PROVIDER.equals(provider)) {
1455 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001456 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001457 } else {
1458 // mock providers
1459 LocationProviderInterface lp = mMockProviders.get(provider);
1460 if (lp != null) {
1461 ProviderProperties properties = lp.getProperties();
1462 if (properties != null) {
1463 if (properties.mRequiresSatellite) {
1464 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001465 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001466 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1467 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001468 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001469 }
1470 }
1471 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001472 }
Victoria Lease37425c32012-10-16 16:08:48 -07001473 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001474 }
1475
Victoria Lease37425c32012-10-16 16:08:48 -07001476 /**
1477 * Throw SecurityException if specified resolution level is insufficient to use the named
1478 * location provider.
1479 *
1480 * @param allowedResolutionLevel resolution level allowed to caller
gomo48f1a642017-11-10 20:35:46 -08001481 * @param providerName the name of the location provider
Victoria Lease37425c32012-10-16 16:08:48 -07001482 */
1483 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1484 String providerName) {
1485 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1486 if (allowedResolutionLevel < requiredResolutionLevel) {
1487 switch (requiredResolutionLevel) {
1488 case RESOLUTION_LEVEL_FINE:
1489 throw new SecurityException("\"" + providerName + "\" location provider " +
1490 "requires ACCESS_FINE_LOCATION permission.");
1491 case RESOLUTION_LEVEL_COARSE:
1492 throw new SecurityException("\"" + providerName + "\" location provider " +
1493 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1494 default:
1495 throw new SecurityException("Insufficient permission for \"" + providerName +
1496 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001497 }
1498 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001499 }
1500
David Christie82edc9b2013-07-19 11:31:42 -07001501 /**
1502 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
1503 * for battery).
1504 */
David Christie40e57822013-07-30 11:36:48 -07001505 private void checkDeviceStatsAllowed() {
David Christie82edc9b2013-07-19 11:31:42 -07001506 mContext.enforceCallingOrSelfPermission(
1507 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
1508 }
1509
David Christie40e57822013-07-30 11:36:48 -07001510 private void checkUpdateAppOpsAllowed() {
1511 mContext.enforceCallingOrSelfPermission(
1512 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
1513 }
1514
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001515 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001516 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1517 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001518 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001519 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001520 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001521 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001522 }
1523 return -1;
1524 }
1525
David Christieb870dbf2015-06-22 12:42:53 -07001526 boolean reportLocationAccessNoThrow(
1527 int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001528 int op = resolutionLevelToOp(allowedResolutionLevel);
1529 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001530 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1531 return false;
1532 }
1533 }
David Christieb870dbf2015-06-22 12:42:53 -07001534
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001535 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001536 }
1537
David Christieb870dbf2015-06-22 12:42:53 -07001538 boolean checkLocationAccess(int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001539 int op = resolutionLevelToOp(allowedResolutionLevel);
1540 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001541 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1542 return false;
1543 }
1544 }
David Christieb870dbf2015-06-22 12:42:53 -07001545
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001546 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001547 }
1548
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001549 /**
Maggie91e630c2018-01-24 17:31:46 -08001550 * Returns all providers by name, including passive and the ones that are not permitted to
1551 * be accessed by the calling activity or are currently disabled, but excluding fused.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001552 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001553 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 public List<String> getAllProviders() {
Maggie91e630c2018-01-24 17:31:46 -08001555 ArrayList<String> out;
1556 synchronized (mLock) {
1557 out = new ArrayList<>(mProviders.size());
1558 for (LocationProviderInterface provider : mProviders) {
1559 String name = provider.getName();
1560 if (LocationManager.FUSED_PROVIDER.equals(name)) {
1561 continue;
1562 }
1563 out.add(name);
1564 }
1565 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001566 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001567 return out;
1568 }
1569
Mike Lockwood03ca2162010-04-01 08:10:09 -07001570 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001571 * Return all providers by name, that match criteria and are optionally
1572 * enabled.
1573 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001574 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001575 @Override
1576 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001577 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001578 ArrayList<String> out;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001579 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07001580 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001581 try {
1582 synchronized (mLock) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001583 out = new ArrayList<>(mProviders.size());
Victoria Leaseb711d572012-10-02 13:14:11 -07001584 for (LocationProviderInterface provider : mProviders) {
1585 String name = provider.getName();
1586 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001587 continue;
1588 }
Victoria Lease37425c32012-10-16 16:08:48 -07001589 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Maggie2a9409e2018-03-21 11:47:28 -07001590 if (enabledOnly
1591 && !isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001592 continue;
1593 }
1594 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
1595 name, provider.getProperties(), criteria)) {
1596 continue;
1597 }
1598 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001599 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001600 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001601 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001602 } finally {
1603 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001604 }
1605
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001606 if (D) Log.d(TAG, "getProviders()=" + out);
1607 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001608 }
1609
1610 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001611 * Return the name of the best provider given a Criteria object.
1612 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001613 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001614 * has been deprecated as well. So this method now uses
1615 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001616 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001617 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001618 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001619 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001620
1621 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001622 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001623 result = pickBest(providers);
1624 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1625 return result;
1626 }
1627 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001628 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001629 result = pickBest(providers);
1630 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1631 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001632 }
1633
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001634 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001635 return null;
1636 }
1637
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001638 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -07001639 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001640 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -07001641 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1642 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001643 } else {
1644 return providers.get(0);
1645 }
1646 }
1647
Nick Pellye0fd6932012-07-11 10:26:13 -07001648 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001649 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1650 LocationProviderInterface p = mProvidersByName.get(provider);
1651 if (p == null) {
1652 throw new IllegalArgumentException("provider=" + provider);
1653 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001654
1655 boolean result = LocationProvider.propertiesMeetCriteria(
1656 p.getName(), p.getProperties(), criteria);
1657 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1658 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001659 }
1660
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001661 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001662 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001663 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001664 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001665 boolean isEnabled = p.isEnabled();
1666 String name = p.getName();
Victoria Lease09eeaec2013-02-05 11:34:13 -08001667 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001668 if (isEnabled && !shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001669 updateProviderListenersLocked(name, false);
David Christieb084fef2013-12-18 14:33:57 -08001670 // If any provider has been disabled, clear all last locations for all providers.
1671 // This is to be on the safe side in case a provider has location derived from
1672 // this disabled provider.
1673 mLastLocation.clear();
1674 mLastLocationCoarseInterval.clear();
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001675 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676 } else if (!isEnabled && shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001677 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001678 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001679 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001680 }
1681 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001682 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1683 UserHandle.ALL);
Tom O'Neill40a86c22013-09-03 18:05:13 -07001684 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1685 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001686 }
1687 }
1688
Amith Yamasanib27528d2014-06-05 15:02:10 -07001689 private void updateProviderListenersLocked(String provider, boolean enabled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 int listeners = 0;
1691
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001692 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001693 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001694
1695 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001696
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001697 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1698 if (records != null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001699 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001700 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001701 // Sends a notification message to the receiver
1702 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1703 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001704 deadReceivers = new ArrayList<>();
Victoria Leaseb711d572012-10-02 13:14:11 -07001705 }
1706 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001708 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001709 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001710 }
1711 }
1712
1713 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001714 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001715 removeUpdatesLocked(deadReceivers.get(i));
1716 }
1717 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 if (enabled) {
1720 p.enable();
1721 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001722 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001723 }
1724 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001725 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727 }
1728
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001729 private void applyRequirementsLocked(String provider) {
1730 LocationProviderInterface p = mProvidersByName.get(provider);
1731 if (p == null) return;
1732
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001734 WorkSource worksource = new WorkSource();
1735 ProviderRequest providerRequest = new ProviderRequest();
1736
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001737 ContentResolver resolver = mContext.getContentResolver();
1738 long backgroundThrottleInterval = Settings.Global.getLong(
1739 resolver,
1740 Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
1741 DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
gomo48f1a642017-11-10 20:35:46 -08001742 // initialize the low power mode to true and set to false if any of the records requires
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001743
gomo48f1a642017-11-10 20:35:46 -08001744 providerRequest.lowPowerMode = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001745 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001746 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001747 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
David Christieb870dbf2015-06-22 12:42:53 -07001748 if (checkLocationAccess(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001749 record.mReceiver.mIdentity.mPid,
1750 record.mReceiver.mIdentity.mUid,
1751 record.mReceiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001752 record.mReceiver.mAllowedResolutionLevel)) {
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001753 LocationRequest locationRequest = record.mRealRequest;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001754 long interval = locationRequest.getInterval();
1755
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001756 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001757 if (!record.mIsForegroundUid) {
1758 interval = Math.max(interval, backgroundThrottleInterval);
1759 }
1760 if (interval != locationRequest.getInterval()) {
1761 locationRequest = new LocationRequest(locationRequest);
1762 locationRequest.setInterval(interval);
1763 }
1764 }
1765
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001766 record.mRequest = locationRequest;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001767 providerRequest.locationRequests.add(locationRequest);
gomo48f1a642017-11-10 20:35:46 -08001768 if (!locationRequest.isLowPowerMode()) {
1769 providerRequest.lowPowerMode = false;
1770 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001771 if (interval < providerRequest.interval) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001772 providerRequest.reportLocation = true;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001773 providerRequest.interval = interval;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001774 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001775 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001776 }
1777 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001778
1779 if (providerRequest.reportLocation) {
1780 // calculate who to blame for power
1781 // This is somewhat arbitrary. We pick a threshold interval
1782 // that is slightly higher that the minimum interval, and
1783 // spread the blame across all applications with a request
1784 // under that threshold.
1785 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1786 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001787 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001788 LocationRequest locationRequest = record.mRequest;
Svet Ganove998c732016-06-10 00:12:38 -07001789
1790 // Don't assign battery blame for update records whose
1791 // client has no permission to receive location data.
1792 if (!providerRequest.locationRequests.contains(locationRequest)) {
1793 continue;
1794 }
1795
Victoria Leaseb711d572012-10-02 13:14:11 -07001796 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07001797 if (record.mReceiver.mWorkSource != null
Narayan Kamath32684dd2018-01-08 17:32:51 +00001798 && isValidWorkSource(record.mReceiver.mWorkSource)) {
David Christie82edc9b2013-07-19 11:31:42 -07001799 worksource.add(record.mReceiver.mWorkSource);
1800 } else {
Narayan Kamath32684dd2018-01-08 17:32:51 +00001801 // Assign blame to caller if there's no WorkSource associated with
1802 // the request or if it's invalid.
David Christie82edc9b2013-07-19 11:31:42 -07001803 worksource.add(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001804 record.mReceiver.mIdentity.mUid,
1805 record.mReceiver.mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07001806 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001807 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001808 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001809 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001810 }
1811 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001812
1813 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1814 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001815 }
1816
Narayan Kamath32684dd2018-01-08 17:32:51 +00001817 /**
1818 * Whether a given {@code WorkSource} associated with a Location request is valid.
1819 */
1820 private static boolean isValidWorkSource(WorkSource workSource) {
1821 if (workSource.size() > 0) {
1822 // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
1823 // by tags.
1824 return workSource.getName(0) != null;
1825 } else {
1826 // For now, make sure callers have supplied an attribution tag for use with
1827 // AppOpsManager. This might be relaxed in the future.
1828 final ArrayList<WorkChain> workChains = workSource.getWorkChains();
1829 return workChains != null && !workChains.isEmpty() &&
1830 workChains.get(0).getAttributionTag() != null;
1831 }
1832 }
1833
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001834 @Override
1835 public String[] getBackgroundThrottlingWhitelist() {
1836 synchronized (mLock) {
1837 return mBackgroundThrottlePackageWhitelist.toArray(
gomo48f1a642017-11-10 20:35:46 -08001838 new String[mBackgroundThrottlePackageWhitelist.size()]);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001839 }
1840 }
1841
1842 private void updateBackgroundThrottlingWhitelistLocked() {
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08001843 String setting = Settings.Global.getString(
gomo48f1a642017-11-10 20:35:46 -08001844 mContext.getContentResolver(),
1845 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08001846 if (setting == null) {
1847 setting = "";
1848 }
1849
1850 mBackgroundThrottlePackageWhitelist.clear();
1851 mBackgroundThrottlePackageWhitelist.addAll(
gomo48f1a642017-11-10 20:35:46 -08001852 SystemConfig.getInstance().getAllowUnthrottledLocation());
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08001853 mBackgroundThrottlePackageWhitelist.addAll(
gomo48f1a642017-11-10 20:35:46 -08001854 Arrays.asList(setting.split(",")));
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08001855 }
1856
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001857 private boolean isThrottlingExemptLocked(Identity identity) {
1858 if (identity.mUid == Process.SYSTEM_UID) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001859 return true;
1860 }
1861
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001862 if (mBackgroundThrottlePackageWhitelist.contains(identity.mPackageName)) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001863 return true;
1864 }
1865
1866 for (LocationProviderProxy provider : mProxyProviders) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001867 if (identity.mPackageName.equals(provider.getConnectedPackageName())) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001868 return true;
1869 }
1870 }
1871
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001872 return false;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001873 }
1874
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001875 private class UpdateRecord {
1876 final String mProvider;
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001877 final LocationRequest mRealRequest; // original request from client
1878 LocationRequest mRequest; // possibly throttled version of the request
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001879 final Receiver mReceiver;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001880 boolean mIsForegroundUid;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001881 Location mLastFixBroadcast;
1882 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001883
1884 /**
1885 * Note: must be constructed with lock held.
1886 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001887 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001888 mProvider = provider;
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001889 mRealRequest = request;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001890 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001891 mReceiver = receiver;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001892 mIsForegroundUid = isImportanceForeground(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001893 mActivityManager.getPackageImportance(mReceiver.mIdentity.mPackageName));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001894
1895 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1896 if (records == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001897 records = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001898 mRecordsByProvider.put(provider, records);
1899 }
1900 if (!records.contains(this)) {
1901 records.add(this);
1902 }
David Christie2ff96af2014-01-30 16:09:37 -08001903
1904 // Update statistics for historical location requests by package/provider
1905 mRequestStatistics.startRequesting(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001906 mReceiver.mIdentity.mPackageName, provider, request.getInterval());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001907 }
1908
1909 /**
David Christie2ff96af2014-01-30 16:09:37 -08001910 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001911 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001912 void disposeLocked(boolean removeReceiver) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001913 mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
David Christie2ff96af2014-01-30 16:09:37 -08001914
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001915 // remove from mRecordsByProvider
1916 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1917 if (globalRecords != null) {
1918 globalRecords.remove(this);
1919 }
1920
1921 if (!removeReceiver) return; // the caller will handle the rest
1922
1923 // remove from Receiver#mUpdateRecords
1924 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1925 if (receiverRecords != null) {
1926 receiverRecords.remove(this.mProvider);
1927
1928 // and also remove the Receiver if it has no more update records
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001929 if (receiverRecords.size() == 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001930 removeUpdatesLocked(mReceiver);
1931 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001932 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001933 }
1934
1935 @Override
1936 public String toString() {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001937 return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
gomo48f1a642017-11-10 20:35:46 -08001938 + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground"
1939 : " background")
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001940 + ")" + " " + mRealRequest + "]";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001941 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001942 }
1943
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001944 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07001945 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001946 IBinder binder = listener.asBinder();
1947 Receiver receiver = mReceivers.get(binder);
1948 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001949 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
1950 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001951 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001952 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001953 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001954 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001955 return null;
1956 }
Wen Jingcb3ab222014-03-27 13:42:59 +08001957 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001958 }
1959 return receiver;
1960 }
1961
David Christie82edc9b2013-07-19 11:31:42 -07001962 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07001963 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001964 Receiver receiver = mReceivers.get(intent);
1965 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001966 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
1967 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001968 mReceivers.put(intent, receiver);
1969 }
1970 return receiver;
1971 }
1972
Victoria Lease37425c32012-10-16 16:08:48 -07001973 /**
1974 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1975 * and consistency requirements.
1976 *
1977 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07001978 * @return a version of request that meets the given resolution and consistency requirements
1979 * @hide
1980 */
gomo48f1a642017-11-10 20:35:46 -08001981 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel,
1982 boolean callerHasLocationHardwarePermission) {
Victoria Lease37425c32012-10-16 16:08:48 -07001983 LocationRequest sanitizedRequest = new LocationRequest(request);
gomo48f1a642017-11-10 20:35:46 -08001984 if (!callerHasLocationHardwarePermission) {
1985 // allow setting low power mode only for callers with location hardware permission
1986 sanitizedRequest.setLowPowerMode(false);
1987 }
Victoria Lease37425c32012-10-16 16:08:48 -07001988 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1989 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001990 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001991 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001992 break;
1993 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001994 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001995 break;
1996 }
1997 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001998 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1999 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002000 }
Victoria Lease37425c32012-10-16 16:08:48 -07002001 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2002 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002003 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002004 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002005 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07002006 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002007 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002008 }
Victoria Lease37425c32012-10-16 16:08:48 -07002009 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002010 }
2011
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002012 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07002013 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002014 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002015 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002016 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07002017 String[] packages = mPackageManager.getPackagesForUid(uid);
2018 if (packages == null) {
2019 throw new SecurityException("invalid UID " + uid);
2020 }
2021 for (String pkg : packages) {
2022 if (packageName.equals(pkg)) return;
2023 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002024 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002025 }
2026
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002027 private void checkPendingIntent(PendingIntent intent) {
2028 if (intent == null) {
2029 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07002030 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002031 }
2032
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002033 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
David Christie40e57822013-07-30 11:36:48 -07002034 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002035 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002036 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002037 } else if (intent != null && listener != null) {
2038 throw new IllegalArgumentException("cannot register both listener and intent");
2039 } else if (intent != null) {
2040 checkPendingIntent(intent);
David Christie40e57822013-07-30 11:36:48 -07002041 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002042 } else {
David Christie40e57822013-07-30 11:36:48 -07002043 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002044 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07002045 }
2046
Nick Pellye0fd6932012-07-11 10:26:13 -07002047 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002048 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
2049 PendingIntent intent, String packageName) {
2050 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2051 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002052 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2053 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2054 request.getProvider());
David Christie82edc9b2013-07-19 11:31:42 -07002055 WorkSource workSource = request.getWorkSource();
Narayan Kamath32684dd2018-01-08 17:32:51 +00002056 if (workSource != null && !workSource.isEmpty()) {
David Christie40e57822013-07-30 11:36:48 -07002057 checkDeviceStatsAllowed();
2058 }
2059 boolean hideFromAppOps = request.getHideFromAppOps();
2060 if (hideFromAppOps) {
2061 checkUpdateAppOpsAllowed();
David Christie82edc9b2013-07-19 11:31:42 -07002062 }
gomo48f1a642017-11-10 20:35:46 -08002063 boolean callerHasLocationHardwarePermission =
2064 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
Maggieaa080f92018-01-04 15:35:11 -08002065 == PERMISSION_GRANTED;
gomo48f1a642017-11-10 20:35:46 -08002066 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
2067 callerHasLocationHardwarePermission);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002068
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002069 final int pid = Binder.getCallingPid();
2070 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002071 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002072 long identity = Binder.clearCallingIdentity();
2073 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002074 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
2075 // a location.
David Christieb870dbf2015-06-22 12:42:53 -07002076 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002077
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002078 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002079 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
David Christie40e57822013-07-30 11:36:48 -07002080 packageName, workSource, hideFromAppOps);
Victoria Lease37425c32012-10-16 16:08:48 -07002081 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04002082 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002083 } finally {
2084 Binder.restoreCallingIdentity(identity);
2085 }
2086 }
2087
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002088 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
2089 int pid, int uid, String packageName) {
2090 // Figure out the provider. Either its explicitly request (legacy use cases), or
2091 // use the fused provider
2092 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2093 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07002094 if (name == null) {
2095 throw new IllegalArgumentException("provider name must not be null");
2096 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07002097
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002098 LocationProviderInterface provider = mProvidersByName.get(name);
2099 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07002100 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002101 }
2102
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002103 UpdateRecord record = new UpdateRecord(name, request, receiver);
gomo48f1a642017-11-10 20:35:46 -08002104 if (D) {
2105 Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
2106 + " " + name + " " + request + " from " + packageName + "(" + uid + " "
2107 + (record.mIsForegroundUid ? "foreground" : "background")
2108 + (isThrottlingExemptLocked(receiver.mIdentity)
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002109 ? " [whitelisted]" : "") + ")");
gomo48f1a642017-11-10 20:35:46 -08002110 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002111
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002112 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
2113 if (oldRecord != null) {
2114 oldRecord.disposeLocked(false);
2115 }
2116
Maggie2a9409e2018-03-21 11:47:28 -07002117 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002118 if (isProviderEnabled) {
2119 applyRequirementsLocked(name);
2120 } else {
2121 // Notify the listener that updates are currently disabled
2122 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002123 }
David Christie0b837452013-07-29 16:02:13 -07002124 // Update the monitoring here just in case multiple location requests were added to the
2125 // same receiver (this request may be high power and the initial might not have been).
2126 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002127 }
2128
Nick Pellye0fd6932012-07-11 10:26:13 -07002129 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002130 public void removeUpdates(ILocationListener listener, PendingIntent intent,
2131 String packageName) {
2132 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002133
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002134 final int pid = Binder.getCallingPid();
2135 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002136
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002137 synchronized (mLock) {
David Christie82edc9b2013-07-19 11:31:42 -07002138 WorkSource workSource = null;
David Christie40e57822013-07-30 11:36:48 -07002139 boolean hideFromAppOps = false;
2140 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
2141 packageName, workSource, hideFromAppOps);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002142
2143 // providers may use public location API's, need to clear identity
2144 long identity = Binder.clearCallingIdentity();
2145 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002146 removeUpdatesLocked(receiver);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002147 } finally {
2148 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002149 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002150 }
2151 }
2152
2153 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08002154 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002155
2156 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
2157 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
2158 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07002159 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002160 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002161 }
2162
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07002163 receiver.updateMonitoring(false);
2164
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002165 // Record which providers were associated with this listener
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002166 HashSet<String> providers = new HashSet<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002167 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
2168 if (oldRecords != null) {
2169 // Call dispose() on the obsolete update records.
2170 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08002171 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002172 record.disposeLocked(false);
2173 }
2174 // Accumulate providers
2175 providers.addAll(oldRecords.keySet());
2176 }
2177
2178 // update provider
2179 for (String provider : providers) {
2180 // If provider is already disabled, don't need to do anything
Victoria Lease09eeaec2013-02-05 11:34:13 -08002181 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002182 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002183 }
2184
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002185 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002186 }
2187 }
2188
Dianne Hackbornc2293022013-02-06 23:14:49 -08002189 private void applyAllProviderRequirementsLocked() {
2190 for (LocationProviderInterface p : mProviders) {
2191 // If provider is already disabled, don't need to do anything
Dianne Hackborn64d41d72013-02-07 00:33:31 -08002192 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08002193 continue;
2194 }
2195
2196 applyRequirementsLocked(p.getName());
2197 }
2198 }
2199
Nick Pellye0fd6932012-07-11 10:26:13 -07002200 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07002201 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002202 if (D) Log.d(TAG, "getLastLocation: " + request);
2203 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002204 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07002205 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002206 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2207 request.getProvider());
2208 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07002209
David Christieb870dbf2015-06-22 12:42:53 -07002210 final int pid = Binder.getCallingPid();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002211 final int uid = Binder.getCallingUid();
2212 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07002213 try {
2214 if (mBlacklist.isBlacklisted(packageName)) {
gomo48f1a642017-11-10 20:35:46 -08002215 if (D) {
2216 Log.d(TAG, "not returning last loc for blacklisted app: " +
2217 packageName);
2218 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002219 return null;
2220 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002221
David Christieb870dbf2015-06-22 12:42:53 -07002222 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08002223 if (D) {
2224 Log.d(TAG, "not returning last loc for no op app: " +
2225 packageName);
2226 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002227 return null;
2228 }
2229
Victoria Leaseb711d572012-10-02 13:14:11 -07002230 synchronized (mLock) {
2231 // Figure out the provider. Either its explicitly request (deprecated API's),
2232 // or use the fused provider
2233 String name = request.getProvider();
2234 if (name == null) name = LocationManager.FUSED_PROVIDER;
2235 LocationProviderInterface provider = mProvidersByName.get(name);
2236 if (provider == null) return null;
2237
Maggie2a9409e2018-03-21 11:47:28 -07002238 if (!isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07002239
David Christie1b9b7b12013-04-15 15:31:11 -07002240 Location location;
2241 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2242 // Make sure that an app with coarse permissions can't get frequent location
2243 // updates by calling LocationManager.getLastKnownLocation repeatedly.
2244 location = mLastLocationCoarseInterval.get(name);
2245 } else {
2246 location = mLastLocation.get(name);
2247 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002248 if (location == null) {
2249 return null;
2250 }
Victoria Lease37425c32012-10-16 16:08:48 -07002251 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
gomo48f1a642017-11-10 20:35:46 -08002252 Location noGPSLocation = location.getExtraLocation(
2253 Location.EXTRA_NO_GPS_LOCATION);
Victoria Leaseb711d572012-10-02 13:14:11 -07002254 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08002255 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07002256 }
Victoria Lease37425c32012-10-16 16:08:48 -07002257 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08002258 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07002259 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002260 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002261 return null;
2262 } finally {
2263 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002264 }
2265 }
2266
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002267 /**
2268 * Provides an interface to inject and set the last location if location is not available
2269 * currently.
2270 *
2271 * This helps in cases where the product (Cars for example) has saved the last known location
2272 * before powering off. This interface lets the client inject the saved location while the GPS
2273 * chipset is getting its first fix, there by improving user experience.
2274 *
2275 * @param location - Location object to inject
2276 * @return true if update was successful, false if not
2277 */
2278 @Override
2279 public boolean injectLocation(Location location) {
2280 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
2281 "Location Hardware permission not granted to inject location");
2282 mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
2283 "Access Fine Location permission not granted to inject Location");
2284
2285 if (location == null) {
2286 if (D) {
2287 Log.d(TAG, "injectLocation(): called with null location");
2288 }
2289 return false;
2290 }
2291 LocationProviderInterface p = null;
2292 String provider = location.getProvider();
2293 if (provider != null) {
2294 p = mProvidersByName.get(provider);
2295 }
2296 if (p == null) {
2297 if (D) {
2298 Log.d(TAG, "injectLocation(): unknown provider");
2299 }
2300 return false;
2301 }
2302 synchronized (mLock) {
2303 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
2304 if (D) {
2305 Log.d(TAG, "Location disabled in Settings for current user:" + mCurrentUserId);
2306 }
2307 return false;
2308 } else {
2309 // NOTE: If last location is already available, location is not injected. If
2310 // provider's normal source (like a GPS chipset) have already provided an output,
2311 // there is no need to inject this location.
2312 if (mLastLocation.get(provider) == null) {
2313 updateLastLocationLocked(location, provider);
2314 } else {
2315 if (D) {
2316 Log.d(TAG, "injectLocation(): Location exists. Not updating");
2317 }
2318 return false;
2319 }
2320 }
2321 }
2322 return true;
2323 }
2324
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002325 @Override
2326 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
2327 String packageName) {
2328 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002329 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2330 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002331 checkPendingIntent(intent);
2332 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002333 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2334 request.getProvider());
gomo48f1a642017-11-10 20:35:46 -08002335 // Require that caller can manage given document
2336 boolean callerHasLocationHardwarePermission =
2337 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
Maggieaa080f92018-01-04 15:35:11 -08002338 == PERMISSION_GRANTED;
gomo48f1a642017-11-10 20:35:46 -08002339 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
2340 callerHasLocationHardwarePermission);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002341
Victoria Lease37425c32012-10-16 16:08:48 -07002342 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002343
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002344 // geo-fence manager uses the public location API, need to clear identity
2345 int uid = Binder.getCallingUid();
Xiaohui Chena4490622015-09-22 15:29:31 -07002346 // TODO: http://b/23822629
2347 if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
Victoria Lease56e675b2012-11-05 19:25:06 -08002348 // temporary measure until geofences work for secondary users
2349 Log.w(TAG, "proximity alerts are currently available only to the primary user");
2350 return;
2351 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002352 long identity = Binder.clearCallingIdentity();
2353 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002354 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
2355 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002356 } finally {
2357 Binder.restoreCallingIdentity(identity);
2358 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002359 }
2360
2361 @Override
2362 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002363 checkPendingIntent(intent);
2364 checkPackageName(packageName);
2365
2366 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
2367
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002368 // geo-fence manager uses the public location API, need to clear identity
2369 long identity = Binder.clearCallingIdentity();
2370 try {
2371 mGeofenceManager.removeFence(geofence, intent);
2372 } finally {
2373 Binder.restoreCallingIdentity(identity);
2374 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002375 }
2376
2377
2378 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002379 public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002380 if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09002381 return false;
2382 }
2383
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002384 try {
Lifu Tang30f95a72016-01-07 23:20:38 -08002385 mGnssStatusProvider.registerGnssStatusCallback(callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002386 } catch (RemoteException e) {
Lifu Tang30f95a72016-01-07 23:20:38 -08002387 Slog.e(TAG, "mGpsStatusProvider.registerGnssStatusCallback failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002388 return false;
2389 }
2390 return true;
2391 }
2392
Nick Pellye0fd6932012-07-11 10:26:13 -07002393 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002394 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002395 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002396 try {
Lifu Tang30f95a72016-01-07 23:20:38 -08002397 mGnssStatusProvider.unregisterGnssStatusCallback(callback);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002398 } catch (Exception e) {
Lifu Tang30f95a72016-01-07 23:20:38 -08002399 Slog.e(TAG, "mGpsStatusProvider.unregisterGnssStatusCallback failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002400 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002401 }
2402 }
2403
Nick Pellye0fd6932012-07-11 10:26:13 -07002404 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002405 public boolean addGnssMeasurementsListener(
gomo48f1a642017-11-10 20:35:46 -08002406 IGnssMeasurementsListener listener, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002407 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07002408 return false;
2409 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002410
2411 synchronized (mLock) {
2412 Identity callerIdentity
2413 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Wyatt Riley11cc7492018-01-17 08:48:27 -08002414 mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002415 long identity = Binder.clearCallingIdentity();
2416 try {
2417 if (isThrottlingExemptLocked(callerIdentity)
2418 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002419 mActivityManager.getPackageImportance(packageName))) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002420 return mGnssMeasurementsProvider.addListener(listener);
2421 }
2422 } finally {
2423 Binder.restoreCallingIdentity(identity);
2424 }
2425
2426 return true;
2427 }
destradaaea8a8a62014-06-23 18:19:03 -07002428 }
2429
2430 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002431 public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
2432 if (mGnssMeasurementsProvider != null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002433 synchronized (mLock) {
Wyatt Riley11cc7492018-01-17 08:48:27 -08002434 mGnssMeasurementsListeners.remove(listener.asBinder());
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002435 mGnssMeasurementsProvider.removeListener(listener);
2436 }
Wei Liu5241a4c2015-05-11 14:00:36 -07002437 }
destradaaea8a8a62014-06-23 18:19:03 -07002438 }
2439
2440 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002441 public boolean addGnssNavigationMessageListener(
2442 IGnssNavigationMessageListener listener,
destradaa4b3e3932014-07-21 18:01:47 -07002443 String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002444 if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07002445 return false;
2446 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002447
2448 synchronized (mLock) {
2449 Identity callerIdentity
gomo48f1a642017-11-10 20:35:46 -08002450 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Wyatt Riley11cc7492018-01-17 08:48:27 -08002451 mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002452 long identity = Binder.clearCallingIdentity();
2453 try {
2454 if (isThrottlingExemptLocked(callerIdentity)
2455 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002456 mActivityManager.getPackageImportance(packageName))) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002457 return mGnssNavigationMessageProvider.addListener(listener);
2458 }
2459 } finally {
2460 Binder.restoreCallingIdentity(identity);
2461 }
2462
2463 return true;
2464 }
destradaa4b3e3932014-07-21 18:01:47 -07002465 }
2466
2467 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002468 public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
2469 if (mGnssNavigationMessageProvider != null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002470 synchronized (mLock) {
Wyatt Riley11cc7492018-01-17 08:48:27 -08002471 mGnssNavigationMessageListeners.remove(listener.asBinder());
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002472 mGnssNavigationMessageProvider.removeListener(listener);
2473 }
Wei Liu5241a4c2015-05-11 14:00:36 -07002474 }
destradaa4b3e3932014-07-21 18:01:47 -07002475 }
2476
2477 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002478 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002479 if (provider == null) {
2480 // throw NullPointerException to remain compatible with previous implementation
2481 throw new NullPointerException();
2482 }
Victoria Lease37425c32012-10-16 16:08:48 -07002483 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2484 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002485
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002486 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04002487 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
Maggieaa080f92018-01-04 15:35:11 -08002488 != PERMISSION_GRANTED)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002489 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2490 }
2491
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002492 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002493 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002494 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07002495
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002496 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002497 }
2498 }
2499
Nick Pellye0fd6932012-07-11 10:26:13 -07002500 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002501 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07002502 if (Binder.getCallingUid() != Process.myUid()) {
2503 throw new SecurityException(
2504 "calling sendNiResponse from outside of the system is not allowed");
2505 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04002506 try {
2507 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002508 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002509 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04002510 return false;
2511 }
2512 }
2513
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002514 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002515 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11002516 * @throws SecurityException if the provider is not allowed to be
gomo48f1a642017-11-10 20:35:46 -08002517 * accessed by the caller
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002518 */
Nick Pellye0fd6932012-07-11 10:26:13 -07002519 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002520 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07002521 if (mProvidersByName.get(provider) == null) {
David Christie2ff96af2014-01-30 16:09:37 -08002522 return null;
Laurent Tub7f9d252012-10-16 14:25:00 -07002523 }
2524
Victoria Lease37425c32012-10-16 16:08:48 -07002525 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2526 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002527
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002528 LocationProviderInterface p;
2529 synchronized (mLock) {
2530 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002531 }
2532
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002533 if (p == null) return null;
2534 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002535 }
2536
Jason Monkb71218a2015-06-17 14:44:39 -04002537 /**
2538 * @return null if the provider does not exist
2539 * @throws SecurityException if the provider is not allowed to be
gomo48f1a642017-11-10 20:35:46 -08002540 * accessed by the caller
Jason Monkb71218a2015-06-17 14:44:39 -04002541 */
2542 @Override
2543 public String getNetworkProviderPackage() {
2544 LocationProviderInterface p;
2545 synchronized (mLock) {
2546 if (mProvidersByName.get(LocationManager.NETWORK_PROVIDER) == null) {
2547 return null;
2548 }
2549 p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
2550 }
2551
2552 if (p instanceof LocationProviderProxy) {
2553 return ((LocationProviderProxy) p).getConnectedPackageName();
2554 }
2555 return null;
2556 }
2557
Maggieaa080f92018-01-04 15:35:11 -08002558 /**
Maggie2a9409e2018-03-21 11:47:28 -07002559 * Returns the current location enabled/disabled status for a user
2560 *
2561 * @param userId the id of the user
2562 * @return true if location is enabled
2563 */
2564 @Override
2565 public boolean isLocationEnabledForUser(int userId) {
2566 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2567 checkInteractAcrossUsersPermission(userId);
2568
2569 long identity = Binder.clearCallingIdentity();
2570 try {
2571 synchronized (mLock) {
2572 final String allowedProviders = Settings.Secure.getStringForUser(
2573 mContext.getContentResolver(),
2574 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
2575 userId);
2576 if (allowedProviders == null) {
2577 return false;
2578 }
2579 final List<String> providerList = Arrays.asList(allowedProviders.split(","));
2580 for(String provider : mRealProviders.keySet()) {
2581 if (provider.equals(LocationManager.PASSIVE_PROVIDER)
2582 || provider.equals(LocationManager.FUSED_PROVIDER)) {
2583 continue;
2584 }
2585 if (providerList.contains(provider)) {
2586 return true;
2587 }
2588 }
2589 return false;
2590 }
2591 } finally {
2592 Binder.restoreCallingIdentity(identity);
2593 }
2594 }
2595
2596 /**
2597 * Enable or disable location for a user
2598 *
2599 * @param enabled true to enable location, false to disable location
2600 * @param userId the id of the user
2601 */
2602 @Override
2603 public void setLocationEnabledForUser(boolean enabled, int userId) {
2604 mContext.enforceCallingPermission(
2605 android.Manifest.permission.WRITE_SECURE_SETTINGS,
2606 "Requires WRITE_SECURE_SETTINGS permission");
2607
2608 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2609 checkInteractAcrossUsersPermission(userId);
2610
2611 long identity = Binder.clearCallingIdentity();
2612 try {
2613 synchronized (mLock) {
2614 final Set<String> allRealProviders = mRealProviders.keySet();
2615 // Update all providers on device plus gps and network provider when disabling
2616 // location
2617 Set<String> allProvidersSet = new ArraySet<>(allRealProviders.size() + 2);
2618 allProvidersSet.addAll(allRealProviders);
2619 // When disabling location, disable gps and network provider that could have been
2620 // enabled by location mode api.
2621 if (enabled == false) {
2622 allProvidersSet.add(LocationManager.GPS_PROVIDER);
2623 allProvidersSet.add(LocationManager.NETWORK_PROVIDER);
2624 }
2625 if (allProvidersSet.isEmpty()) {
2626 return;
2627 }
2628 // to ensure thread safety, we write the provider name with a '+' or '-'
2629 // and let the SettingsProvider handle it rather than reading and modifying
2630 // the list of enabled providers.
2631 final String prefix = enabled ? "+" : "-";
2632 StringBuilder locationProvidersAllowed = new StringBuilder();
2633 for (String provider : allProvidersSet) {
2634 if (provider.equals(LocationManager.PASSIVE_PROVIDER)
2635 || provider.equals(LocationManager.FUSED_PROVIDER)) {
2636 continue;
2637 }
2638 locationProvidersAllowed.append(prefix);
2639 locationProvidersAllowed.append(provider);
2640 locationProvidersAllowed.append(",");
2641 }
2642 // Remove the trailing comma
2643 locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
2644 Settings.Secure.putStringForUser(
2645 mContext.getContentResolver(),
2646 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
2647 locationProvidersAllowed.toString(),
2648 userId);
2649 }
2650 } finally {
2651 Binder.restoreCallingIdentity(identity);
2652 }
2653 }
2654
2655 /**
2656 * Returns the current enabled/disabled status of a location provider and user
2657 *
2658 * @param provider name of the provider
2659 * @param userId the id of the user
2660 * @return true if the provider exists and is enabled
2661 */
2662 @Override
2663 public boolean isProviderEnabledForUser(String provider, int userId) {
2664 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2665 checkInteractAcrossUsersPermission(userId);
2666
2667 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2668 // so we discourage its use
2669 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
2670
2671 int uid = Binder.getCallingUid();
2672 synchronized (mLock) {
2673 LocationProviderInterface p = mProvidersByName.get(provider);
2674 return p != null
2675 && isAllowedByUserSettingsLocked(provider, uid, userId);
2676 }
2677 }
2678
2679 /**
2680 * Enable or disable a single location provider.
2681 *
2682 * @param provider name of the provider
2683 * @param enabled true to enable the provider. False to disable the provider
2684 * @param userId the id of the user to set
2685 * @return true if the value was set, false on errors
2686 */
2687 @Override
2688 public boolean setProviderEnabledForUser(String provider, boolean enabled, int userId) {
2689 mContext.enforceCallingPermission(
2690 android.Manifest.permission.WRITE_SECURE_SETTINGS,
2691 "Requires WRITE_SECURE_SETTINGS permission");
2692
2693 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2694 checkInteractAcrossUsersPermission(userId);
2695
2696 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2697 // so we discourage its use
2698 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
2699
2700 long identity = Binder.clearCallingIdentity();
2701 try {
2702 synchronized (mLock) {
2703 // No such provider exists
2704 if (!mProvidersByName.containsKey(provider)) return false;
2705
2706 // If it is a test provider, do not write to Settings.Secure
2707 if (mMockProviders.containsKey(provider)) {
2708 setTestProviderEnabled(provider, enabled);
2709 return true;
2710 }
2711
2712 // to ensure thread safety, we write the provider name with a '+' or '-'
2713 // and let the SettingsProvider handle it rather than reading and modifying
2714 // the list of enabled providers.
2715 String providerChange = (enabled ? "+" : "-") + provider;
2716 return Settings.Secure.putStringForUser(
2717 mContext.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
2718 providerChange, userId);
2719 }
2720 } finally {
2721 Binder.restoreCallingIdentity(identity);
2722 }
2723 }
2724
2725 /**
Maggieaa080f92018-01-04 15:35:11 -08002726 * Read location provider status from Settings.Secure
2727 *
2728 * @param provider the location provider to query
2729 * @param userId the user id to query
2730 * @return true if the provider is enabled
2731 */
2732 private boolean isLocationProviderEnabledForUser(String provider, int userId) {
2733 long identity = Binder.clearCallingIdentity();
2734 try {
2735 // Use system settings
2736 ContentResolver cr = mContext.getContentResolver();
2737 String allowedProviders = Settings.Secure.getStringForUser(
2738 cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId);
2739 return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
2740 } finally {
2741 Binder.restoreCallingIdentity(identity);
2742 }
2743 }
2744
2745 /**
Maggie2a9409e2018-03-21 11:47:28 -07002746 * Method for checking INTERACT_ACROSS_USERS permission if specified user id is not the same as
2747 * current user id
2748 *
2749 * @param userId the user id to get or set value
2750 */
2751 private void checkInteractAcrossUsersPermission(int userId) {
2752 int uid = Binder.getCallingUid();
2753 if (UserHandle.getUserId(uid) != userId) {
2754 if (ActivityManager.checkComponentPermission(
2755 android.Manifest.permission.INTERACT_ACROSS_USERS, uid, -1, true)
2756 != PERMISSION_GRANTED) {
2757 throw new SecurityException("Requires INTERACT_ACROSS_USERS permission");
2758 }
2759 }
2760 }
2761
2762 /**
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002763 * Returns "true" if the UID belongs to a bound location provider.
2764 *
2765 * @param uid the uid
2766 * @return true if uid belongs to a bound location provider
2767 */
2768 private boolean isUidALocationProvider(int uid) {
2769 if (uid == Process.SYSTEM_UID) {
2770 return true;
2771 }
2772 if (mGeocodeProvider != null) {
David Christie1f141c12014-05-14 15:11:15 -07002773 if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002774 }
2775 for (LocationProviderProxy proxy : mProxyProviders) {
David Christie1f141c12014-05-14 15:11:15 -07002776 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002777 }
2778 return false;
2779 }
2780
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002781 private void checkCallerIsProvider() {
2782 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
Maggieaa080f92018-01-04 15:35:11 -08002783 == PERMISSION_GRANTED) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002784 return;
2785 }
2786
2787 // Previously we only used the INSTALL_LOCATION_PROVIDER
2788 // check. But that is system or signature
2789 // protection level which is not flexible enough for
2790 // providers installed oustide the system image. So
2791 // also allow providers with a UID matching the
2792 // currently bound package name
2793
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002794 if (isUidALocationProvider(Binder.getCallingUid())) {
2795 return;
2796 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002797
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002798 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2799 "or UID of a currently bound location provider");
2800 }
2801
David Christie1f141c12014-05-14 15:11:15 -07002802 /**
2803 * Returns true if the given package belongs to the given uid.
2804 */
2805 private boolean doesUidHavePackage(int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002806 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002807 return false;
2808 }
David Christie1f141c12014-05-14 15:11:15 -07002809 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2810 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002811 return false;
2812 }
David Christie1f141c12014-05-14 15:11:15 -07002813 for (String name : packageNames) {
2814 if (packageName.equals(name)) {
2815 return true;
2816 }
2817 }
2818 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002819 }
2820
Nick Pellye0fd6932012-07-11 10:26:13 -07002821 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05002822 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002823 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04002824
Nick Pelly2eeeec22012-07-18 13:13:37 -07002825 if (!location.isComplete()) {
2826 Log.w(TAG, "Dropping incomplete location: " + location);
2827 return;
2828 }
2829
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002830 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2831 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05002832 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002833 mLocationHandler.sendMessageAtFrontOfQueue(m);
2834 }
2835
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002836
Laurent Tu75defb62012-11-01 16:21:52 -07002837 private static boolean shouldBroadcastSafe(
2838 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002839 // Always broadcast the first update
2840 if (lastLoc == null) {
2841 return true;
2842 }
2843
Nick Pellyf1be6862012-05-15 10:53:42 -07002844 // Check whether sufficient time has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002845 long minTime = record.mRealRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002846 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2847 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002848 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002849 return false;
2850 }
2851
2852 // Check whether sufficient distance has been traveled
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002853 double minDistance = record.mRealRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002854 if (minDistance > 0.0) {
2855 if (loc.distanceTo(lastLoc) <= minDistance) {
2856 return false;
2857 }
2858 }
2859
Laurent Tu75defb62012-11-01 16:21:52 -07002860 // Check whether sufficient number of udpates is left
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002861 if (record.mRealRequest.getNumUpdates() <= 0) {
Laurent Tu75defb62012-11-01 16:21:52 -07002862 return false;
2863 }
2864
2865 // Check whether the expiry date has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002866 return record.mRealRequest.getExpireAt() >= now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002867 }
2868
Mike Lockwooda4903f22010-02-17 06:42:23 -05002869 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002870 if (D) Log.d(TAG, "incoming location: " + location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002871 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05002872 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
Laurent Tu60ec50a2012-10-04 17:00:10 -07002873 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002874 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002875 if (p == null) return;
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002876 updateLastLocationLocked(location, provider);
2877 // mLastLocation should have been updated from the updateLastLocationLocked call above.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002878 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002879 if (lastLocation == null) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002880 Log.e(TAG, "handleLocationChangedLocked() updateLastLocation failed");
2881 return;
Mike Lockwood4e50b782009-04-03 08:24:43 -07002882 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002883
David Christie1b9b7b12013-04-15 15:31:11 -07002884 // Update last known coarse interval location if enough time has passed.
2885 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2886 if (lastLocationCoarseInterval == null) {
2887 lastLocationCoarseInterval = new Location(location);
2888 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2889 }
2890 long timeDiffNanos = location.getElapsedRealtimeNanos()
2891 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2892 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
2893 lastLocationCoarseInterval.set(location);
2894 }
2895 // Don't ever return a coarse location that is more recent than the allowed update
2896 // interval (i.e. don't allow an app to keep registering and unregistering for
2897 // location updates to overcome the minimum interval).
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002898 Location noGPSLocation =
David Christie1b9b7b12013-04-15 15:31:11 -07002899 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2900
Laurent Tu60ec50a2012-10-04 17:00:10 -07002901 // Skip if there are no UpdateRecords for this provider.
2902 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2903 if (records == null || records.size() == 0) return;
2904
Victoria Lease09016ab2012-09-16 12:33:15 -07002905 // Fetch coarse location
2906 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07002907 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002908 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2909 }
2910
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002911 // Fetch latest status update time
2912 long newStatusUpdateTime = p.getStatusUpdateTime();
2913
David Christie2ff96af2014-01-30 16:09:37 -08002914 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002915 Bundle extras = new Bundle();
2916 int status = p.getStatus(extras);
2917
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002918 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002919 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07002920
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002921 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002922 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002923 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07002924 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07002925
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002926 int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
2927 if (!isCurrentProfile(receiverUserId)
2928 && !isUidALocationProvider(receiver.mIdentity.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07002929 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07002930 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07002931 " (current user: " + mCurrentUserId + ", app: " +
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002932 receiver.mIdentity.mPackageName + ")");
Victoria Leaseb711d572012-10-02 13:14:11 -07002933 }
2934 continue;
2935 }
2936
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002937 if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
gomo48f1a642017-11-10 20:35:46 -08002938 if (D) {
2939 Log.d(TAG, "skipping loc update for blacklisted app: " +
2940 receiver.mIdentity.mPackageName);
2941 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002942 continue;
2943 }
2944
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002945 if (!reportLocationAccessNoThrow(
2946 receiver.mIdentity.mPid,
2947 receiver.mIdentity.mUid,
2948 receiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002949 receiver.mAllowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08002950 if (D) {
2951 Log.d(TAG, "skipping loc update for no op app: " +
2952 receiver.mIdentity.mPackageName);
2953 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002954 continue;
2955 }
2956
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002957 Location notifyLocation;
Victoria Lease37425c32012-10-16 16:08:48 -07002958 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2959 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002960 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07002961 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002962 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002963 if (notifyLocation != null) {
2964 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07002965 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002966 if (lastLoc == null) {
2967 lastLoc = new Location(notifyLocation);
2968 r.mLastFixBroadcast = lastLoc;
2969 } else {
2970 lastLoc.set(notifyLocation);
2971 }
2972 if (!receiver.callLocationChangedLocked(notifyLocation)) {
2973 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2974 receiverDead = true;
2975 }
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002976 r.mRealRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002977 }
2978 }
2979
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002980 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002981 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07002982 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002983
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002984 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002985 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002986 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08002987 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07002988 }
2989 }
2990
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002991 // track expired records
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002992 if (r.mRealRequest.getNumUpdates() <= 0 || r.mRealRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002993 if (deadUpdateRecords == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002994 deadUpdateRecords = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002995 }
2996 deadUpdateRecords.add(r);
2997 }
2998 // track dead receivers
2999 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07003000 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003001 deadReceivers = new ArrayList<>();
Mike Lockwood03ca2162010-04-01 08:10:09 -07003002 }
3003 if (!deadReceivers.contains(receiver)) {
3004 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003005 }
3006 }
3007 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003008
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003009 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003010 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003011 for (Receiver receiver : deadReceivers) {
3012 removeUpdatesLocked(receiver);
3013 }
3014 }
3015 if (deadUpdateRecords != null) {
3016 for (UpdateRecord r : deadUpdateRecords) {
3017 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003018 }
Victoria Lease8b38b292012-12-04 15:04:43 -08003019 applyRequirementsLocked(provider);
3020 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003021 }
3022
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003023 /**
3024 * Updates last location with the given location
3025 *
3026 * @param location new location to update
3027 * @param provider Location provider to update for
3028 */
3029 private void updateLastLocationLocked(Location location, String provider) {
3030 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3031 Location lastNoGPSLocation;
3032 Location lastLocation = mLastLocation.get(provider);
3033 if (lastLocation == null) {
3034 lastLocation = new Location(provider);
3035 mLastLocation.put(provider, lastLocation);
3036 } else {
3037 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3038 if (noGPSLocation == null && lastNoGPSLocation != null) {
3039 // New location has no no-GPS location: adopt last no-GPS location. This is set
3040 // directly into location because we do not want to notify COARSE clients.
3041 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
3042 }
3043 }
3044 lastLocation.set(location);
3045 }
3046
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003047 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08003048 public LocationWorkerHandler(Looper looper) {
3049 super(looper, null, true);
3050 }
3051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003052 @Override
3053 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003054 switch (msg.what) {
3055 case MSG_LOCATION_CHANGED:
3056 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
3057 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003058 }
3059 }
3060 }
3061
Victoria Lease54ca7ae2013-01-08 09:39:50 -08003062 private boolean isMockProvider(String provider) {
3063 synchronized (mLock) {
3064 return mMockProviders.containsKey(provider);
3065 }
3066 }
3067
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003068 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08003069 // create a working copy of the incoming Location so that the service can modify it without
3070 // disturbing the caller's copy
3071 Location myLocation = new Location(location);
3072 String provider = myLocation.getProvider();
3073
3074 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
3075 // bit if location did not come from a mock provider because passive/fused providers can
3076 // forward locations from mock providers, and should not grant them legitimacy in doing so.
3077 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
3078 myLocation.setIsFromMockProvider(true);
3079 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08003080
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003081 synchronized (mLock) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08003082 if (isAllowedByCurrentUserSettingsLocked(provider)) {
3083 if (!passive) {
3084 // notify passive provider of the new location
3085 mPassiveProvider.updateLocation(myLocation);
3086 }
Victoria Lease54ca7ae2013-01-08 09:39:50 -08003087 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003088 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003089 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003090 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003091
Mike Lockwoode97ae402010-09-29 15:23:46 -04003092 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
3093 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003094 public void onPackageDisappeared(String packageName, int reason) {
3095 // remove all receivers associated with this package name
3096 synchronized (mLock) {
3097 ArrayList<Receiver> deadReceivers = null;
3098
3099 for (Receiver receiver : mReceivers.values()) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003100 if (receiver.mIdentity.mPackageName.equals(packageName)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003101 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003102 deadReceivers = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003103 }
3104 deadReceivers.add(receiver);
3105 }
3106 }
3107
3108 // perform removal outside of mReceivers loop
3109 if (deadReceivers != null) {
3110 for (Receiver receiver : deadReceivers) {
3111 removeUpdatesLocked(receiver);
3112 }
3113 }
3114 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003115 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04003116 };
3117
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003118 // Geocoder
3119
Nick Pellye0fd6932012-07-11 10:26:13 -07003120 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04003121 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07003122 return mGeocodeProvider != null;
3123 }
3124
Nick Pellye0fd6932012-07-11 10:26:13 -07003125 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003126 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003127 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003128 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003129 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
3130 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003131 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003132 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003133 }
3134
Mike Lockwooda55c3212009-04-15 11:10:11 -04003135
Nick Pellye0fd6932012-07-11 10:26:13 -07003136 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003137 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04003138 double lowerLeftLatitude, double lowerLeftLongitude,
3139 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003140 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003141
3142 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003143 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
3144 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
3145 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003146 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003147 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003148 }
3149
3150 // Mock Providers
3151
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003152 private boolean canCallerAccessMockLocation(String opPackageName) {
3153 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
3154 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003155 }
3156
Nick Pellye0fd6932012-07-11 10:26:13 -07003157 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003158 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
3159 if (!canCallerAccessMockLocation(opPackageName)) {
3160 return;
3161 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003162
Mike Lockwooda4903f22010-02-17 06:42:23 -05003163 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
3164 throw new IllegalArgumentException("Cannot mock the passive location provider");
3165 }
3166
Mike Lockwood86328a92009-10-23 08:38:25 -04003167 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003168 synchronized (mLock) {
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003169 // remove the real provider if we are replacing GPS or network provider
3170 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07003171 || LocationManager.NETWORK_PROVIDER.equals(name)
3172 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05003173 LocationProviderInterface p = mProvidersByName.get(name);
3174 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003175 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003176 }
3177 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003178 addTestProviderLocked(name, properties);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003179 updateProvidersLocked();
3180 }
Mike Lockwood86328a92009-10-23 08:38:25 -04003181 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003182 }
3183
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003184 private void addTestProviderLocked(String name, ProviderProperties properties) {
3185 if (mProvidersByName.get(name) != null) {
3186 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
3187 }
3188 MockProvider provider = new MockProvider(name, this, properties);
3189 addProviderLocked(provider);
3190 mMockProviders.put(name, provider);
3191 mLastLocation.put(name, null);
3192 mLastLocationCoarseInterval.put(name, null);
3193 }
3194
Nick Pellye0fd6932012-07-11 10:26:13 -07003195 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003196 public void removeTestProvider(String provider, String opPackageName) {
3197 if (!canCallerAccessMockLocation(opPackageName)) {
3198 return;
3199 }
3200
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003201 synchronized (mLock) {
Tom O'Neill07ee5d12014-03-03 17:48:35 -08003202
3203 // These methods can't be called after removing the test provider, so first make sure
Tom O'Neillfe6d3c52014-03-04 08:26:17 -08003204 // we don't leave anything dangling.
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003205 clearTestProviderEnabled(provider, opPackageName);
3206 clearTestProviderLocation(provider, opPackageName);
3207 clearTestProviderStatus(provider, opPackageName);
Tom O'Neill07ee5d12014-03-03 17:48:35 -08003208
You Kima6d0b6f2012-10-28 03:58:44 +09003209 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003210 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003211 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3212 }
Mike Lockwood86328a92009-10-23 08:38:25 -04003213 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003214 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003215
3216 // reinstate real provider if available
3217 LocationProviderInterface realProvider = mRealProviders.get(provider);
3218 if (realProvider != null) {
3219 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003220 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003221 mLastLocation.put(provider, null);
David Christie1b9b7b12013-04-15 15:31:11 -07003222 mLastLocationCoarseInterval.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003223 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04003224 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003225 }
3226 }
3227
Nick Pellye0fd6932012-07-11 10:26:13 -07003228 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003229 public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
3230 if (!canCallerAccessMockLocation(opPackageName)) {
3231 return;
3232 }
3233
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003234 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003235 MockProvider mockProvider = mMockProviders.get(provider);
3236 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003237 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3238 }
Tom O'Neilla206a0f2016-12-15 10:26:28 -08003239
3240 // Ensure that the location is marked as being mock. There's some logic to do this in
3241 // handleLocationChanged(), but it fails if loc has the wrong provider (bug 33091107).
3242 Location mock = new Location(loc);
3243 mock.setIsFromMockProvider(true);
3244
3245 if (!TextUtils.isEmpty(loc.getProvider()) && !provider.equals(loc.getProvider())) {
3246 // The location has an explicit provider that is different from the mock provider
3247 // name. The caller may be trying to fool us via bug 33091107.
3248 EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
3249 provider + "!=" + loc.getProvider());
3250 }
3251
Mike Lockwood95427cd2009-05-07 13:27:54 -04003252 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
3253 long identity = Binder.clearCallingIdentity();
Tom O'Neilla206a0f2016-12-15 10:26:28 -08003254 mockProvider.setLocation(mock);
Mike Lockwood95427cd2009-05-07 13:27:54 -04003255 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003256 }
3257 }
3258
Nick Pellye0fd6932012-07-11 10:26:13 -07003259 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003260 public void clearTestProviderLocation(String provider, String opPackageName) {
3261 if (!canCallerAccessMockLocation(opPackageName)) {
3262 return;
3263 }
3264
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003265 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003266 MockProvider mockProvider = mMockProviders.get(provider);
3267 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003268 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3269 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003270 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003271 }
3272 }
3273
Nick Pellye0fd6932012-07-11 10:26:13 -07003274 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003275 public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
3276 if (!canCallerAccessMockLocation(opPackageName)) {
3277 return;
3278 }
Maggie2a9409e2018-03-21 11:47:28 -07003279 setTestProviderEnabled(provider, enabled);
3280 }
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003281
Maggie2a9409e2018-03-21 11:47:28 -07003282 /** Enable or disable a test location provider. */
3283 private void setTestProviderEnabled(String provider, boolean enabled) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003284 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003285 MockProvider mockProvider = mMockProviders.get(provider);
3286 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003287 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3288 }
Mike Lockwood86328a92009-10-23 08:38:25 -04003289 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003290 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003291 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003292 mEnabledProviders.add(provider);
3293 mDisabledProviders.remove(provider);
3294 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003295 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003296 mEnabledProviders.remove(provider);
3297 mDisabledProviders.add(provider);
3298 }
3299 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04003300 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003301 }
3302 }
3303
Nick Pellye0fd6932012-07-11 10:26:13 -07003304 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003305 public void clearTestProviderEnabled(String provider, String opPackageName) {
3306 if (!canCallerAccessMockLocation(opPackageName)) {
3307 return;
3308 }
3309
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003310 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003311 MockProvider mockProvider = mMockProviders.get(provider);
3312 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003313 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3314 }
Mike Lockwood86328a92009-10-23 08:38:25 -04003315 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003316 mEnabledProviders.remove(provider);
3317 mDisabledProviders.remove(provider);
3318 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04003319 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003320 }
3321 }
3322
Nick Pellye0fd6932012-07-11 10:26:13 -07003323 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003324 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
3325 String opPackageName) {
3326 if (!canCallerAccessMockLocation(opPackageName)) {
3327 return;
3328 }
3329
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003330 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003331 MockProvider mockProvider = mMockProviders.get(provider);
3332 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003333 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3334 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003335 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003336 }
3337 }
3338
Nick Pellye0fd6932012-07-11 10:26:13 -07003339 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003340 public void clearTestProviderStatus(String provider, String opPackageName) {
3341 if (!canCallerAccessMockLocation(opPackageName)) {
3342 return;
3343 }
3344
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003345 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003346 MockProvider mockProvider = mMockProviders.get(provider);
3347 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003348 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3349 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003350 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003351 }
3352 }
3353
3354 private void log(String log) {
3355 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003356 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003357 }
3358 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003359
3360 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003361 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06003362 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Nick Pellye0fd6932012-07-11 10:26:13 -07003363
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003364 synchronized (mLock) {
Siddharth Raybb608c82017-03-16 11:33:34 -07003365 if (args.length > 0 && args[0].equals("--gnssmetrics")) {
3366 if (mGnssMetricsProvider != null) {
3367 pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
3368 }
3369 return;
3370 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003371 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003372 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003373 for (Receiver receiver : mReceivers.values()) {
3374 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003375 }
David Christie2ff96af2014-01-30 16:09:37 -08003376 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003377 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
3378 pw.println(" " + entry.getKey() + ":");
3379 for (UpdateRecord record : entry.getValue()) {
3380 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003381 }
3382 }
Wyatt Riley11cc7492018-01-17 08:48:27 -08003383 pw.println(" Active GnssMeasurement Listeners:");
3384 for (Identity identity : mGnssMeasurementsListeners.values()) {
3385 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3386 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3387 }
3388 pw.println(" Active GnssNavigationMessage Listeners:");
3389 for (Identity identity : mGnssNavigationMessageListeners.values()) {
3390 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3391 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3392 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003393 pw.println(" Overlay Provider Packages:");
3394 for (LocationProviderInterface provider : mProviders) {
3395 if (provider instanceof LocationProviderProxy) {
3396 pw.println(" " + provider.getName() + ": "
3397 + ((LocationProviderProxy) provider).getConnectedPackageName());
3398 }
3399 }
David Christie2ff96af2014-01-30 16:09:37 -08003400 pw.println(" Historical Records by Provider:");
3401 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
3402 : mRequestStatistics.statistics.entrySet()) {
3403 PackageProviderKey key = entry.getKey();
3404 PackageStatistics stats = entry.getValue();
3405 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
3406 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003407 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003408 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
3409 String provider = entry.getKey();
3410 Location location = entry.getValue();
3411 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003412 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003413
David Christie1b9b7b12013-04-15 15:31:11 -07003414 pw.println(" Last Known Locations Coarse Intervals:");
3415 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
3416 String provider = entry.getKey();
3417 Location location = entry.getValue();
3418 pw.println(" " + provider + ": " + location);
3419 }
3420
Nick Pellye0fd6932012-07-11 10:26:13 -07003421 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003423 if (mEnabledProviders.size() > 0) {
3424 pw.println(" Enabled Providers:");
3425 for (String i : mEnabledProviders) {
3426 pw.println(" " + i);
3427 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003428
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003429 }
3430 if (mDisabledProviders.size() > 0) {
3431 pw.println(" Disabled Providers:");
3432 for (String i : mDisabledProviders) {
3433 pw.println(" " + i);
3434 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003435 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07003436 pw.append(" ");
3437 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003438 if (mMockProviders.size() > 0) {
3439 pw.println(" Mock Providers:");
3440 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003441 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003442 }
3443 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003444
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08003445 if (!mBackgroundThrottlePackageWhitelist.isEmpty()) {
3446 pw.println(" Throttling Whitelisted Packages:");
3447 for (String packageName : mBackgroundThrottlePackageWhitelist) {
3448 pw.println(" " + packageName);
3449 }
3450 }
3451
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003452 pw.append(" fudger: ");
gomo48f1a642017-11-10 20:35:46 -08003453 mLocationFudger.dump(fd, pw, args);
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003454
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003455 if (args.length > 0 && "short".equals(args[0])) {
3456 return;
3457 }
gomo48f1a642017-11-10 20:35:46 -08003458 for (LocationProviderInterface provider : mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003459 pw.print(provider.getName() + " Internal State");
3460 if (provider instanceof LocationProviderProxy) {
3461 LocationProviderProxy proxy = (LocationProviderProxy) provider;
3462 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003463 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003464 pw.println(":");
3465 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003466 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08003467 if (mGnssBatchingInProgress) {
3468 pw.println(" GNSS batching in progress");
3469 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003470 }
3471 }
3472}