blob: 4a72c1f87db631966b2d3ed94f1a49fe9ea9f8bc [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
Soonil Nagarkar7decfb62017-01-18 12:18:49 -080019import android.app.ActivityManager;
Wyatt Rileycf879db2017-01-12 13:57:38 -080020import android.annotation.NonNull;
Svet Ganovadc1cf42015-06-15 16:36:24 -070021import android.content.pm.PackageManagerInternal;
destradaaea8a8a62014-06-23 18:19:03 -070022import com.android.internal.content.PackageMonitor;
23import com.android.internal.location.ProviderProperties;
24import com.android.internal.location.ProviderRequest;
25import com.android.internal.os.BackgroundThread;
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -070026import com.android.internal.util.ArrayUtils;
destradaaa4fa3b52014-07-09 10:46:39 -070027import com.android.server.location.ActivityRecognitionProxy;
destradaaea8a8a62014-06-23 18:19:03 -070028import com.android.server.location.FlpHardwareProvider;
29import com.android.server.location.FusedProxy;
30import com.android.server.location.GeocoderProxy;
31import com.android.server.location.GeofenceManager;
32import com.android.server.location.GeofenceProxy;
Lifu Tang818aa2c2016-02-01 01:52:00 -080033import com.android.server.location.GnssLocationProvider;
34import com.android.server.location.GnssMeasurementsProvider;
35import com.android.server.location.GnssNavigationMessageProvider;
destradaaea8a8a62014-06-23 18:19:03 -070036import com.android.server.location.LocationBlacklist;
37import com.android.server.location.LocationFudger;
38import com.android.server.location.LocationProviderInterface;
39import com.android.server.location.LocationProviderProxy;
40import com.android.server.location.LocationRequestStatistics;
41import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
42import com.android.server.location.LocationRequestStatistics.PackageStatistics;
43import com.android.server.location.MockProvider;
44import com.android.server.location.PassiveProvider;
45
Dianne Hackborna06de0f2012-12-11 16:34:47 -080046import android.app.AppOpsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.app.PendingIntent;
Victoria Lease38389b62012-09-30 11:44:22 -070048import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.content.ContentResolver;
50import android.content.Context;
51import android.content.Intent;
Victoria Lease38389b62012-09-30 11:44:22 -070052import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070053import android.content.pm.ApplicationInfo;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050054import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.content.pm.PackageManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070056import android.content.pm.PackageManager.NameNotFoundException;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050057import android.content.pm.ResolveInfo;
58import android.content.pm.Signature;
Mike Lockwood628fd6d2010-01-25 22:46:13 -050059import android.content.res.Resources;
Brian Muramatsubb95cb92012-08-29 10:43:21 -070060import android.database.ContentObserver;
destradaaa4fa3b52014-07-09 10:46:39 -070061import android.hardware.location.ActivityRecognitionHardware;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070063import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050064import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070065import android.location.Geofence;
Wyatt Rileycf879db2017-01-12 13:57:38 -080066import android.location.IBatchedLocationCallback;
Lifu Tang818aa2c2016-02-01 01:52:00 -080067import android.location.IGnssMeasurementsListener;
Lifu Tang30f95a72016-01-07 23:20:38 -080068import android.location.IGnssStatusListener;
69import android.location.IGnssStatusProvider;
Wei Liu5241a4c2015-05-11 14:00:36 -070070import android.location.IGpsGeofenceHardware;
Lifu Tang818aa2c2016-02-01 01:52:00 -080071import android.location.IGnssNavigationMessageListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.location.ILocationListener;
73import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040074import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075import android.location.Location;
76import android.location.LocationManager;
77import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070078import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079import android.os.Binder;
80import android.os.Bundle;
81import android.os.Handler;
82import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070083import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084import android.os.Message;
85import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070086import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070088import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070089import android.os.UserHandle;
Amith Yamasanib27528d2014-06-05 15:02:10 -070090import android.os.UserManager;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070091import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092import android.provider.Settings;
Tom O'Neilla206a0f2016-12-15 10:26:28 -080093import android.text.TextUtils;
94import android.util.EventLog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080096import android.util.Slog;
Amith Yamasanib27528d2014-06-05 15:02:10 -070097
Mike Lockwood43e33f22010-03-26 10:41:48 -040098import java.io.FileDescriptor;
99import java.io.PrintWriter;
100import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700101import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400102import java.util.HashMap;
103import java.util.HashSet;
104import java.util.List;
105import java.util.Map;
Wyatt Rileycf879db2017-01-12 13:57:38 -0800106import java.util.NoSuchElementException;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400107import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108
109/**
110 * The service class that manages LocationProviders and issues location
111 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 */
Victoria Lease5cd731a2012-12-19 15:04:21 -0800113public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -0800115 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700116
117 private static final String WAKELOCK_KEY = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118
Victoria Lease37425c32012-10-16 16:08:48 -0700119 // Location resolution level: no location data whatsoever
120 private static final int RESOLUTION_LEVEL_NONE = 0;
121 // Location resolution level: coarse location data only
122 private static final int RESOLUTION_LEVEL_COARSE = 1;
123 // Location resolution level: fine location data
124 private static final int RESOLUTION_LEVEL_FINE = 2;
125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700127 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700129 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400130 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700131 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
132
133 private static final String NETWORK_LOCATION_SERVICE_ACTION =
Stan Chesnutt39062dd2013-07-22 14:33:30 -0700134 "com.android.location.service.v3.NetworkLocationProvider";
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700135 private static final String FUSED_LOCATION_SERVICE_ACTION =
136 "com.android.location.service.FusedLocationProvider";
137
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800138 private static final String GMSCORE_PACKAGE = "com.android.google.gms";
139
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700140 private static final int MSG_LOCATION_CHANGED = 1;
141
David Christie1b9b7b12013-04-15 15:31:11 -0700142 private static final long NANOS_PER_MILLI = 1000000L;
143
David Christie0b837452013-07-29 16:02:13 -0700144 // The maximum interval a location request can have and still be considered "high power".
145 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
146
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800147 // default background throttling interval if not overriden in settings
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800148 private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 10 * 60 * 1000;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800149
Nick Pellyf1be6862012-05-15 10:53:42 -0700150 // Location Providers may sometimes deliver location updates
151 // slightly faster that requested - provide grace period so
152 // we don't unnecessarily filter events that are otherwise on
153 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700154 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700155
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700156 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
157
158 private final Context mContext;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800159 private final AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700160
161 // used internally for synchronization
162 private final Object mLock = new Object();
163
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700164 // --- fields below are final after systemRunning() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700165 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700166 private GeofenceManager mGeofenceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700167 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700168 private PowerManager mPowerManager;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800169 private ActivityManager mActivityManager;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700170 private UserManager mUserManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700171 private GeocoderProxy mGeocodeProvider;
Lifu Tang30f95a72016-01-07 23:20:38 -0800172 private IGnssStatusProvider mGnssStatusProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700173 private INetInitiatedListener mNetInitiatedListener;
174 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700175 private PassiveProvider mPassiveProvider; // track passive provider for special cases
176 private LocationBlacklist mBlacklist;
Lifu Tang818aa2c2016-02-01 01:52:00 -0800177 private GnssMeasurementsProvider mGnssMeasurementsProvider;
178 private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
Wei Liu5241a4c2015-05-11 14:00:36 -0700179 private IGpsGeofenceHardware mGpsGeofenceProxy;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700180
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700181 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 // Set of providers that are explicitly enabled
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700183 // Only used by passive, fused & test. Network & GPS are controlled separately, and not listed.
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800184 private final Set<String> mEnabledProviders = new HashSet<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185
186 // Set of providers that are explicitly disabled
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800187 private final Set<String> mDisabledProviders = new HashSet<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700189 // Mock (test) providers
190 private final HashMap<String, MockProvider> mMockProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800191 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700193 // all receivers
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800194 private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700196 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500197 private final ArrayList<LocationProviderInterface> mProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800198 new ArrayList<>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400199
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700200 // real providers, saved here when mocked out
201 private final HashMap<String, LocationProviderInterface> mRealProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800202 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700204 // mapping from provider name to provider
205 private final HashMap<String, LocationProviderInterface> mProvidersByName =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800206 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700208 // mapping from provider name to all its UpdateRecords
209 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800210 new HashMap<>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700211
David Christie2ff96af2014-01-30 16:09:37 -0800212 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
213
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700214 // mapping from provider name to last known location
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800215 private final HashMap<String, Location> mLastLocation = new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216
David Christie1b9b7b12013-04-15 15:31:11 -0700217 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
218 // locations stored here are not fudged for coarse permissions.
219 private final HashMap<String, Location> mLastLocationCoarseInterval =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800220 new HashMap<>();
David Christie1b9b7b12013-04-15 15:31:11 -0700221
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800222 // all providers that operate over proxy, for authorizing incoming location and whitelisting
223 // throttling
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700224 private final ArrayList<LocationProviderProxy> mProxyProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800225 new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800227 private String[] mBackgroundThrottlePackageWhitelist = new String[]{};
228
Victoria Lease38389b62012-09-30 11:44:22 -0700229 // current active user on the device - other users are denied location data
Xiaohui Chena4490622015-09-22 15:29:31 -0700230 private int mCurrentUserId = UserHandle.USER_SYSTEM;
231 private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_SYSTEM };
Victoria Lease38389b62012-09-30 11:44:22 -0700232
Lifu Tang9363b942016-02-16 18:07:00 -0800233 private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
Lifu Tang82f893d2016-01-21 18:15:33 -0800234
Wyatt Rileycf879db2017-01-12 13:57:38 -0800235 private GnssLocationProvider.GnssBatchingProvider mGnssBatchingProvider;
236 private IBatchedLocationCallback mGnssBatchingCallback;
237 private LinkedCallback mGnssBatchingDeathCallback;
238 private boolean mGnssBatchingInProgress = false;
239
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700240 public LocationManagerService(Context context) {
241 super();
242 mContext = context;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800243 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800244
Svet Ganovadc1cf42015-06-15 16:36:24 -0700245 // Let the package manager query which are the default location
246 // providers as they get certain permissions granted by default.
247 PackageManagerInternal packageManagerInternal = LocalServices.getService(
248 PackageManagerInternal.class);
249 packageManagerInternal.setLocationPackagesProvider(
250 new PackageManagerInternal.PackagesProvider() {
251 @Override
252 public String[] getPackages(int userId) {
253 return mContext.getResources().getStringArray(
254 com.android.internal.R.array.config_locationProviderPackageNames);
255 }
256 });
257
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700258 if (D) Log.d(TAG, "Constructed");
259
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700260 // most startup is deferred until systemRunning()
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700261 }
262
Svetoslav Ganova0027152013-06-25 14:59:53 -0700263 public void systemRunning() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700264 synchronized (mLock) {
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700265 if (D) Log.d(TAG, "systemRunning()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700266
Victoria Lease5cd731a2012-12-19 15:04:21 -0800267 // fetch package manager
268 mPackageManager = mContext.getPackageManager();
269
Victoria Lease0aa28602013-05-29 15:28:26 -0700270 // fetch power manager
271 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800272
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800273 // fetch activity manager
274 mActivityManager
275 = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
276
Victoria Lease5cd731a2012-12-19 15:04:21 -0800277 // prepare worker thread
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700278 mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
Victoria Lease5cd731a2012-12-19 15:04:21 -0800279
280 // prepare mLocationHandler's dependents
281 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
282 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
283 mBlacklist.init();
284 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
285
Dianne Hackbornc2293022013-02-06 23:14:49 -0800286 // Monitor for app ops mode changes.
Dianne Hackborn9bb0ee92013-09-22 12:31:38 -0700287 AppOpsManager.OnOpChangedListener callback
288 = new AppOpsManager.OnOpChangedInternalListener() {
289 public void onOpChanged(int op, String packageName) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800290 synchronized (mLock) {
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700291 for (Receiver receiver : mReceivers.values()) {
292 receiver.updateMonitoring(true);
293 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800294 applyAllProviderRequirementsLocked();
295 }
296 }
297 };
298 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
299
David Christieb870dbf2015-06-22 12:42:53 -0700300 PackageManager.OnPermissionsChangedListener permissionListener
301 = new PackageManager.OnPermissionsChangedListener() {
302 @Override
303 public void onPermissionsChanged(final int uid) {
304 synchronized (mLock) {
305 applyAllProviderRequirementsLocked();
306 }
307 }
308 };
309 mPackageManager.addOnPermissionsChangeListener(permissionListener);
310
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800311 // listen for background/foreground changes
312 ActivityManager.OnUidImportanceListener uidImportanceListener
313 = new ActivityManager.OnUidImportanceListener() {
314 @Override
315 public void onUidImportance(int uid, int importance) {
316 boolean foreground = isImportanceForeground(importance);
317 HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
318 synchronized (mLock) {
319 for (Map.Entry<String, ArrayList<UpdateRecord>> entry
320 : mRecordsByProvider.entrySet()) {
321 String provider = entry.getKey();
322 for (UpdateRecord record : entry.getValue()) {
323 if (record.mReceiver.mUid == uid
324 && record.mIsForegroundUid != foreground) {
325 if (D) Log.d(TAG, "request from uid " + uid + " is now "
326 + (foreground ? "foreground" : "background)"));
327 record.mIsForegroundUid = foreground;
328
329 if (!isThrottlingExemptLocked(record.mReceiver)) {
330 affectedProviders.add(provider);
331 }
332 }
333 }
334 }
335 for (String provider : affectedProviders) {
336 applyRequirementsLocked(provider);
337 }
338 }
339
340 }
341 };
342 mActivityManager.addOnUidImportanceListener(uidImportanceListener,
343 ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE);
344
Amith Yamasanib27528d2014-06-05 15:02:10 -0700345 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
346 updateUserProfiles(mCurrentUserId);
347
Victoria Lease5cd731a2012-12-19 15:04:21 -0800348 // prepare providers
349 loadProvidersLocked();
350 updateProvidersLocked();
351 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700352
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700353 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700354 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700355 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700356 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800357 @Override
358 public void onChange(boolean selfChange) {
359 synchronized (mLock) {
360 updateProvidersLocked();
361 }
362 }
363 }, UserHandle.USER_ALL);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800364 mContext.getContentResolver().registerContentObserver(
365 Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS),
366 true,
367 new ContentObserver(mLocationHandler) {
368 @Override
369 public void onChange(boolean selfChange) {
370 synchronized (mLock) {
371 updateProvidersLocked();
372 }
373 }
374 }, UserHandle.USER_ALL);
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800375 mContext.getContentResolver().registerContentObserver(
376 Settings.Global.getUriFor(
377 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
378 true,
379 new ContentObserver(mLocationHandler) {
380 @Override
381 public void onChange(boolean selfChange) {
382 synchronized (mLock) {
383 String setting = Settings.Global.getString(
384 mContext.getContentResolver(),
385 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
386 if (setting == null) {
387 setting = "";
388 }
389
390 mBackgroundThrottlePackageWhitelist = setting.split(",");
391 updateProvidersLocked();
392 }
393 }
394 }, UserHandle.USER_ALL);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800395 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700396
Victoria Lease38389b62012-09-30 11:44:22 -0700397 // listen for user change
398 IntentFilter intentFilter = new IntentFilter();
399 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700400 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
401 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
destradaab9026982015-08-27 17:34:54 -0700402 intentFilter.addAction(Intent.ACTION_SHUTDOWN);
Victoria Lease38389b62012-09-30 11:44:22 -0700403
404 mContext.registerReceiverAsUser(new BroadcastReceiver() {
405 @Override
406 public void onReceive(Context context, Intent intent) {
407 String action = intent.getAction();
408 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
409 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
Amith Yamasanib27528d2014-06-05 15:02:10 -0700410 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
411 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
412 updateUserProfiles(mCurrentUserId);
destradaab9026982015-08-27 17:34:54 -0700413 } else if (Intent.ACTION_SHUTDOWN.equals(action)) {
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700414 // shutdown only if UserId indicates whole system, not just one user
415 if(D) Log.d(TAG, "Shutdown received with UserId: " + getSendingUserId());
416 if (getSendingUserId() == UserHandle.USER_ALL) {
417 shutdownComponents();
418 }
Victoria Lease38389b62012-09-30 11:44:22 -0700419 }
420 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800421 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700422 }
423
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800424 private static boolean isImportanceForeground(int importance) {
425 return importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
426 }
427
Amith Yamasanib27528d2014-06-05 15:02:10 -0700428 /**
destradaab9026982015-08-27 17:34:54 -0700429 * Provides a way for components held by the {@link LocationManagerService} to clean-up
430 * gracefully on system's shutdown.
431 *
432 * NOTES:
433 * 1) Only provides a chance to clean-up on an opt-in basis. This guarantees back-compat
434 * support for components that do not wish to handle such event.
435 */
436 private void shutdownComponents() {
437 if(D) Log.d(TAG, "Shutting down components...");
438
439 LocationProviderInterface gpsProvider = mProvidersByName.get(LocationManager.GPS_PROVIDER);
440 if (gpsProvider != null && gpsProvider.isEnabled()) {
441 gpsProvider.disable();
442 }
443
destradaa2e385072015-10-14 16:45:58 -0700444 // it is needed to check if FLP HW provider is supported before accessing the instance, this
445 // avoids an exception to be thrown by the singleton factory method
446 if (FlpHardwareProvider.isSupported()) {
447 FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
destradaab9026982015-08-27 17:34:54 -0700448 flpHardwareProvider.cleanup();
449 }
450 }
451
452 /**
Amith Yamasanib27528d2014-06-05 15:02:10 -0700453 * Makes a list of userids that are related to the current user. This is
454 * relevant when using managed profiles. Otherwise the list only contains
455 * the current user.
456 *
457 * @param currentUserId the current user, who might have an alter-ego.
458 */
459 void updateUserProfiles(int currentUserId) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700460 int[] profileIds = mUserManager.getProfileIdsWithDisabled(currentUserId);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700461 synchronized (mLock) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700462 mCurrentUserProfiles = profileIds;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700463 }
464 }
465
466 /**
467 * Checks if the specified userId matches any of the current foreground
468 * users stored in mCurrentUserProfiles.
469 */
470 private boolean isCurrentProfile(int userId) {
471 synchronized (mLock) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700472 return ArrayUtils.contains(mCurrentUserProfiles, userId);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700473 }
474 }
475
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500476 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
477 PackageManager pm = mContext.getPackageManager();
478 String systemPackageName = mContext.getPackageName();
479 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
480
481 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
482 new Intent(FUSED_LOCATION_SERVICE_ACTION),
483 PackageManager.GET_META_DATA, mCurrentUserId);
484 for (ResolveInfo rInfo : rInfos) {
485 String packageName = rInfo.serviceInfo.packageName;
486
487 // Check that the signature is in the list of supported sigs. If it's not in
488 // this list the standard provider binding logic won't bind to it.
489 try {
490 PackageInfo pInfo;
491 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
492 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
493 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
494 ", but has wrong signature, ignoring");
495 continue;
496 }
497 } catch (NameNotFoundException e) {
498 Log.e(TAG, "missing package: " + packageName);
499 continue;
500 }
501
502 // Get the version info
503 if (rInfo.serviceInfo.metaData == null) {
504 Log.w(TAG, "Found fused provider without metadata: " + packageName);
505 continue;
506 }
507
508 int version = rInfo.serviceInfo.metaData.getInt(
509 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
510 if (version == 0) {
511 // This should be the fallback fused location provider.
512
513 // Make sure it's in the system partition.
514 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
515 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
516 continue;
517 }
518
519 // Check that the fallback is signed the same as the OS
520 // as a proxy for coreApp="true"
521 if (pm.checkSignatures(systemPackageName, packageName)
522 != PackageManager.SIGNATURE_MATCH) {
523 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
524 + packageName);
525 continue;
526 }
527
528 // Found a valid fallback.
529 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
530 return;
531 } else {
532 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
533 }
534 }
535
536 throw new IllegalStateException("Unable to find a fused location provider that is in the "
537 + "system partition with version 0 and signed with the platform certificate. "
538 + "Such a package is needed to provide a default fused location provider in the "
539 + "event that no other fused location provider has been installed or is currently "
540 + "available. For example, coreOnly boot mode when decrypting the data "
541 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
542 }
543
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700544 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700545 // create a passive location provider, which is always enabled
546 PassiveProvider passiveProvider = new PassiveProvider(this);
547 addProviderLocked(passiveProvider);
548 mEnabledProviders.add(passiveProvider.getName());
549 mPassiveProvider = passiveProvider;
550
Lifu Tang30f95a72016-01-07 23:20:38 -0800551 if (GnssLocationProvider.isSupported()) {
Wei Liu5241a4c2015-05-11 14:00:36 -0700552 // Create a gps location provider
Lifu Tang30f95a72016-01-07 23:20:38 -0800553 GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext, this,
Wei Liu5241a4c2015-05-11 14:00:36 -0700554 mLocationHandler.getLooper());
Lifu Tang9363b942016-02-16 18:07:00 -0800555 mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
Wyatt Rileycf879db2017-01-12 13:57:38 -0800556 mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800557 mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
558 mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
559 addProviderLocked(gnssProvider);
560 mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProvider);
Lifu Tang818aa2c2016-02-01 01:52:00 -0800561 mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
562 mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800563 mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700564 }
565
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700566 /*
567 Load package name(s) containing location provider support.
568 These packages can contain services implementing location providers:
569 Geocoder Provider, Network Location Provider, and
570 Fused Location Provider. They will each be searched for
571 service components implementing these providers.
572 The location framework also has support for installation
573 of new location providers at run-time. The new package does not
574 have to be explicitly listed here, however it must have a signature
575 that matches the signature of at least one package on this list.
576 */
577 Resources resources = mContext.getResources();
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800578 ArrayList<String> providerPackageNames = new ArrayList<>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500579 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700580 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500581 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
582 Arrays.toString(pkgs));
583 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
584
585 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700586
587 // bind to network provider
588 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
589 mContext,
590 LocationManager.NETWORK_PROVIDER,
591 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700592 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
593 com.android.internal.R.string.config_networkLocationProviderPackageName,
594 com.android.internal.R.array.config_locationProviderPackageNames,
595 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700596 if (networkProvider != null) {
597 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
598 mProxyProviders.add(networkProvider);
599 addProviderLocked(networkProvider);
600 } else {
601 Slog.w(TAG, "no network location provider found");
602 }
603
604 // bind to fused provider
605 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
606 mContext,
607 LocationManager.FUSED_PROVIDER,
608 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700609 com.android.internal.R.bool.config_enableFusedLocationOverlay,
610 com.android.internal.R.string.config_fusedLocationProviderPackageName,
611 com.android.internal.R.array.config_locationProviderPackageNames,
612 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700613 if (fusedLocationProvider != null) {
614 addProviderLocked(fusedLocationProvider);
615 mProxyProviders.add(fusedLocationProvider);
616 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700617 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700618 } else {
619 Slog.e(TAG, "no fused location provider found",
620 new IllegalStateException("Location service needs a fused location provider"));
621 }
622
623 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700624 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
625 com.android.internal.R.bool.config_enableGeocoderOverlay,
626 com.android.internal.R.string.config_geocoderProviderPackageName,
627 com.android.internal.R.array.config_locationProviderPackageNames,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800628 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700629 if (mGeocodeProvider == null) {
630 Slog.e(TAG, "no geocoder provider found");
631 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700632
destradaaa4fa3b52014-07-09 10:46:39 -0700633 // bind to fused hardware provider if supported
destradaabeea4422014-07-30 18:17:21 -0700634 // in devices without support, requesting an instance of FlpHardwareProvider will raise an
635 // exception, so make sure we only do that when supported
636 FlpHardwareProvider flpHardwareProvider;
destradaa5ce66d82014-05-28 18:24:08 -0700637 if (FlpHardwareProvider.isSupported()) {
destradaabeea4422014-07-30 18:17:21 -0700638 flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
destradaaf9a274c2014-07-25 15:11:56 -0700639 FusedProxy fusedProxy = FusedProxy.createAndBind(
640 mContext,
641 mLocationHandler,
642 flpHardwareProvider.getLocationHardware(),
643 com.android.internal.R.bool.config_enableHardwareFlpOverlay,
644 com.android.internal.R.string.config_hardwareFlpPackageName,
645 com.android.internal.R.array.config_locationProviderPackageNames);
646 if (fusedProxy == null) {
destradaa6b4893a2016-05-03 15:33:43 -0700647 Slog.d(TAG, "Unable to bind FusedProxy.");
destradaaf9a274c2014-07-25 15:11:56 -0700648 }
destradaacfbdcd22014-04-30 11:29:11 -0700649 } else {
destradaabeea4422014-07-30 18:17:21 -0700650 flpHardwareProvider = null;
destradaa6b4893a2016-05-03 15:33:43 -0700651 Slog.d(TAG, "FLP HAL not supported");
destradaaf9a274c2014-07-25 15:11:56 -0700652 }
653
654 // bind to geofence provider
655 GeofenceProxy provider = GeofenceProxy.createAndBind(
656 mContext,com.android.internal.R.bool.config_enableGeofenceOverlay,
657 com.android.internal.R.string.config_geofenceProviderPackageName,
658 com.android.internal.R.array.config_locationProviderPackageNames,
659 mLocationHandler,
Wei Liu5241a4c2015-05-11 14:00:36 -0700660 mGpsGeofenceProxy,
destradaabeea4422014-07-30 18:17:21 -0700661 flpHardwareProvider != null ? flpHardwareProvider.getGeofenceHardware() : null);
destradaaf9a274c2014-07-25 15:11:56 -0700662 if (provider == null) {
destradaa6b4893a2016-05-03 15:33:43 -0700663 Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
destradaa0682809a2013-08-12 18:50:30 -0700664 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900665
destradaa6e2fe752015-06-23 17:25:53 -0700666 // bind to hardware activity recognition
667 boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported();
668 ActivityRecognitionHardware activityRecognitionHardware = null;
669 if (activityRecognitionHardwareIsSupported) {
670 activityRecognitionHardware = ActivityRecognitionHardware.getInstance(mContext);
destradaaa4fa3b52014-07-09 10:46:39 -0700671 } else {
destradaa6b4893a2016-05-03 15:33:43 -0700672 Slog.d(TAG, "Hardware Activity-Recognition not supported.");
destradaaa4fa3b52014-07-09 10:46:39 -0700673 }
destradaa6e2fe752015-06-23 17:25:53 -0700674 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
675 mContext,
676 mLocationHandler,
677 activityRecognitionHardwareIsSupported,
678 activityRecognitionHardware,
679 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
680 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
681 com.android.internal.R.array.config_locationProviderPackageNames);
682 if (proxy == null) {
destradaa6b4893a2016-05-03 15:33:43 -0700683 Slog.d(TAG, "Unable to bind ActivityRecognitionProxy.");
destradaa6e2fe752015-06-23 17:25:53 -0700684 }
destradaaa4fa3b52014-07-09 10:46:39 -0700685
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900686 String[] testProviderStrings = resources.getStringArray(
687 com.android.internal.R.array.config_testLocationProviders);
688 for (String testProviderString : testProviderStrings) {
689 String fragments[] = testProviderString.split(",");
690 String name = fragments[0].trim();
691 if (mProvidersByName.get(name) != null) {
692 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
693 }
694 ProviderProperties properties = new ProviderProperties(
695 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
696 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
697 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
698 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
699 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
700 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
701 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
702 Integer.parseInt(fragments[8]) /* powerRequirement */,
703 Integer.parseInt(fragments[9]) /* accuracy */);
704 addTestProviderLocked(name, properties);
705 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700706 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700707
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700709 * Called when the device's active user changes.
710 * @param userId the new active user's UserId
711 */
712 private void switchUser(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800713 if (mCurrentUserId == userId) {
714 return;
715 }
Victoria Lease83762d22012-10-03 13:51:17 -0700716 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800717 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700718 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700719 mLastLocation.clear();
David Christie1b9b7b12013-04-15 15:31:11 -0700720 mLastLocationCoarseInterval.clear();
Victoria Leaseb711d572012-10-02 13:14:11 -0700721 for (LocationProviderInterface p : mProviders) {
Amith Yamasanib27528d2014-06-05 15:02:10 -0700722 updateProviderListenersLocked(p.getName(), false);
Victoria Leaseb711d572012-10-02 13:14:11 -0700723 }
Victoria Lease38389b62012-09-30 11:44:22 -0700724 mCurrentUserId = userId;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700725 updateUserProfiles(userId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700726 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700727 }
728 }
729
730 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
732 * location updates.
733 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700734 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700735 final int mUid; // uid of receiver
736 final int mPid; // pid of receiver
737 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700738 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700739
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 final ILocationListener mListener;
741 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -0700742 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
David Christie40e57822013-07-30 11:36:48 -0700743 final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800744 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700745
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800746 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700747
David Christie0b837452013-07-29 16:02:13 -0700748 // True if app ops has started monitoring this receiver for locations.
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700749 boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -0700750 // True if app ops has started monitoring this receiver for high power (gps) locations.
751 boolean mOpHighPowerMonitoring;
Mike Lockwood48f17512009-04-23 09:12:08 -0700752 int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -0700753 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800754
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700755 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -0700756 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700759 if (listener != null) {
760 mKey = listener.asBinder();
761 } else {
762 mKey = intent;
763 }
Victoria Lease37425c32012-10-16 16:08:48 -0700764 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700765 mUid = uid;
766 mPid = pid;
767 mPackageName = packageName;
David Christie82edc9b2013-07-19 11:31:42 -0700768 if (workSource != null && workSource.size() <= 0) {
769 workSource = null;
770 }
771 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -0700772 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -0700773
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700774 updateMonitoring(true);
775
Victoria Lease0aa28602013-05-29 15:28:26 -0700776 // construct/configure wakelock
777 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -0700778 if (workSource == null) {
779 workSource = new WorkSource(mUid, mPackageName);
780 }
781 mWakeLock.setWorkSource(workSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782 }
783
784 @Override
785 public boolean equals(Object otherObj) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800786 return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787 }
788
789 @Override
790 public int hashCode() {
791 return mKey.hashCode();
792 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400793
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 @Override
795 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700796 StringBuilder s = new StringBuilder();
797 s.append("Reciever[");
798 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700800 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800801 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700802 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700804 for (String p : mUpdateRecords.keySet()) {
805 s.append(" ").append(mUpdateRecords.get(p).toString());
806 }
807 s.append("]");
808 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 }
810
David Christie15b31912013-08-13 15:54:32 -0700811 /**
812 * Update AppOp monitoring for this receiver.
813 *
814 * @param allow If true receiver is currently active, if false it's been removed.
815 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700816 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -0700817 if (mHideFromAppOps) {
818 return;
819 }
820
David Christie15b31912013-08-13 15:54:32 -0700821 boolean requestingLocation = false;
822 boolean requestingHighPowerLocation = false;
823 if (allow) {
824 // See if receiver has any enabled update records. Also note if any update records
825 // are high power (has a high power provider with an interval under a threshold).
826 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
827 if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) {
828 requestingLocation = true;
829 LocationProviderInterface locationProvider
David Christie2ff96af2014-01-30 16:09:37 -0800830 = mProvidersByName.get(updateRecord.mProvider);
David Christie15b31912013-08-13 15:54:32 -0700831 ProviderProperties properties = locationProvider != null
832 ? locationProvider.getProperties() : null;
833 if (properties != null
834 && properties.mPowerRequirement == Criteria.POWER_HIGH
835 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
836 requestingHighPowerLocation = true;
837 break;
838 }
839 }
840 }
841 }
842
David Christie0b837452013-07-29 16:02:13 -0700843 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -0700844 mOpMonitoring = updateMonitoring(
845 requestingLocation,
846 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700847 AppOpsManager.OP_MONITOR_LOCATION);
848
849 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -0700850 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -0700851 mOpHighPowerMonitoring = updateMonitoring(
852 requestingHighPowerLocation,
853 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700854 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -0700855 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -0700856 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -0700857 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
858 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
859 }
David Christie0b837452013-07-29 16:02:13 -0700860 }
861
862 /**
863 * Update AppOps monitoring for a single location request and op type.
864 *
865 * @param allowMonitoring True if monitoring is allowed for this request/op.
866 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
867 * @param op AppOps code for the op to update.
868 * @return True if monitoring is on for this request/op after updating.
869 */
870 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
871 int op) {
872 if (!currentlyMonitoring) {
873 if (allowMonitoring) {
874 return mAppOps.startOpNoThrow(op, mUid, mPackageName)
875 == AppOpsManager.MODE_ALLOWED;
876 }
877 } else {
878 if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
879 != AppOpsManager.MODE_ALLOWED) {
880 mAppOps.finishOp(op, mUid, mPackageName);
881 return false;
882 }
883 }
884
885 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700886 }
887
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800888 public boolean isListener() {
889 return mListener != null;
890 }
891
892 public boolean isPendingIntent() {
893 return mPendingIntent != null;
894 }
895
896 public ILocationListener getListener() {
897 if (mListener != null) {
898 return mListener;
899 }
900 throw new IllegalStateException("Request for non-existent listener");
901 }
902
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800903 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
904 if (mListener != null) {
905 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700906 synchronized (this) {
907 // synchronize to ensure incrementPendingBroadcastsLocked()
908 // is called before decrementPendingBroadcasts()
909 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700910 // call this after broadcasting so we do not increment
911 // if we throw an exeption.
912 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700913 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914 } catch (RemoteException e) {
915 return false;
916 }
917 } else {
918 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800919 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800920 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
921 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700922 synchronized (this) {
923 // synchronize to ensure incrementPendingBroadcastsLocked()
924 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700925 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700926 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700927 // call this after broadcasting so we do not increment
928 // if we throw an exeption.
929 incrementPendingBroadcastsLocked();
930 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931 } catch (PendingIntent.CanceledException e) {
932 return false;
933 }
934 }
935 return true;
936 }
937
938 public boolean callLocationChangedLocked(Location location) {
939 if (mListener != null) {
940 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700941 synchronized (this) {
942 // synchronize to ensure incrementPendingBroadcastsLocked()
943 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800944 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700945 // call this after broadcasting so we do not increment
946 // if we throw an exeption.
947 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700948 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949 } catch (RemoteException e) {
950 return false;
951 }
952 } else {
953 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800954 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800955 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700956 synchronized (this) {
957 // synchronize to ensure incrementPendingBroadcastsLocked()
958 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700959 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700960 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700961 // call this after broadcasting so we do not increment
962 // if we throw an exeption.
963 incrementPendingBroadcastsLocked();
964 }
965 } catch (PendingIntent.CanceledException e) {
966 return false;
967 }
968 }
969 return true;
970 }
971
972 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -0700973 // First update AppOp monitoring.
974 // An app may get/lose location access as providers are enabled/disabled.
975 updateMonitoring(true);
976
Mike Lockwood48f17512009-04-23 09:12:08 -0700977 if (mListener != null) {
978 try {
979 synchronized (this) {
980 // synchronize to ensure incrementPendingBroadcastsLocked()
981 // is called before decrementPendingBroadcasts()
982 if (enabled) {
983 mListener.onProviderEnabled(provider);
984 } else {
985 mListener.onProviderDisabled(provider);
986 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700987 // call this after broadcasting so we do not increment
988 // if we throw an exeption.
989 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700990 }
991 } catch (RemoteException e) {
992 return false;
993 }
994 } else {
995 Intent providerIntent = new Intent();
996 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
997 try {
998 synchronized (this) {
999 // synchronize to ensure incrementPendingBroadcastsLocked()
1000 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001001 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -07001002 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -07001003 // call this after broadcasting so we do not increment
1004 // if we throw an exeption.
1005 incrementPendingBroadcastsLocked();
1006 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 } catch (PendingIntent.CanceledException e) {
1008 return false;
1009 }
1010 }
1011 return true;
1012 }
1013
Nick Pellyf1be6862012-05-15 10:53:42 -07001014 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001016 if (D) Log.d(TAG, "Location listener died");
1017
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001018 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 removeUpdatesLocked(this);
1020 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001021 synchronized (this) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001022 clearPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001023 }
1024 }
1025
Nick Pellye0fd6932012-07-11 10:26:13 -07001026 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001027 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1028 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001029 synchronized (this) {
1030 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001031 }
1032 }
1033
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001034 // this must be called while synchronized by caller in a synchronized block
1035 // containing the sending of the broadcaset
1036 private void incrementPendingBroadcastsLocked() {
1037 if (mPendingBroadcasts++ == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001038 mWakeLock.acquire();
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001039 }
1040 }
1041
1042 private void decrementPendingBroadcastsLocked() {
1043 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001044 if (mWakeLock.isHeld()) {
1045 mWakeLock.release();
1046 }
1047 }
1048 }
1049
1050 public void clearPendingBroadcastsLocked() {
1051 if (mPendingBroadcasts > 0) {
1052 mPendingBroadcasts = 0;
1053 if (mWakeLock.isHeld()) {
1054 mWakeLock.release();
1055 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001056 }
1057 }
1058 }
1059
Nick Pellye0fd6932012-07-11 10:26:13 -07001060 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001061 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001062 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -04001063 //the receiver list if it is not found. If it is not found then the
1064 //LocationListener was removed when it had a pending broadcast and should
1065 //not be added back.
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001066 synchronized (mLock) {
1067 IBinder binder = listener.asBinder();
1068 Receiver receiver = mReceivers.get(binder);
1069 if (receiver != null) {
1070 synchronized (receiver) {
1071 // so wakelock calls will succeed
1072 long identity = Binder.clearCallingIdentity();
1073 receiver.decrementPendingBroadcastsLocked();
1074 Binder.restoreCallingIdentity(identity);
David Christie2ff96af2014-01-30 16:09:37 -08001075 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001076 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 }
1078 }
1079
Lifu Tang82f893d2016-01-21 18:15:33 -08001080 /**
Lifu Tang9363b942016-02-16 18:07:00 -08001081 * Returns the system information of the GNSS hardware.
Lifu Tang82f893d2016-01-21 18:15:33 -08001082 */
1083 @Override
Lifu Tang9363b942016-02-16 18:07:00 -08001084 public int getGnssYearOfHardware() {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001085 if (mGnssSystemInfoProvider != null) {
Lifu Tang9363b942016-02-16 18:07:00 -08001086 return mGnssSystemInfoProvider.getGnssYearOfHardware();
Lifu Tang82f893d2016-01-21 18:15:33 -08001087 } else {
1088 return 0;
1089 }
1090 }
1091
Wyatt Rileycf879db2017-01-12 13:57:38 -08001092 /**
1093 * Runs some checks for GNSS (FINE) level permissions, used by several methods which directly
1094 * (try to) access GNSS information at this layer.
1095 */
1096 private boolean hasGnssPermissions(String packageName) {
1097 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1098 checkResolutionLevelIsSufficientForProviderUse(
1099 allowedResolutionLevel,
1100 LocationManager.GPS_PROVIDER);
1101
1102 int pid = Binder.getCallingPid();
1103 int uid = Binder.getCallingUid();
1104 long identity = Binder.clearCallingIdentity();
1105 boolean hasLocationAccess;
1106 try {
1107 hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1108 } finally {
1109 Binder.restoreCallingIdentity(identity);
1110 }
1111
1112 return hasLocationAccess;
1113 }
1114
1115 /**
1116 * Returns the GNSS batching size, if available.
1117 */
1118 @Override
1119 public int getGnssBatchSize(String packageName) {
1120 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1121 "Location Hardware permission not granted to access hardware batching");
1122
1123 if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
1124 return mGnssBatchingProvider.getSize();
1125 } else {
1126 return 0;
1127 }
1128 }
1129
1130 /**
1131 * Adds a callback for GNSS Batching events, if permissions allow, which are transported
1132 * to potentially multiple listeners by the BatchedLocationCallbackTransport above this.
1133 */
1134 @Override
1135 public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
1136 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1137 "Location Hardware permission not granted to access hardware batching");
1138
1139 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1140 return false;
1141 }
1142
1143 mGnssBatchingCallback = callback;
1144 mGnssBatchingDeathCallback = new LinkedCallback(callback);
1145 try {
1146 callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
1147 } catch (RemoteException e) {
1148 // if the remote process registering the listener is already dead, just swallow the
1149 // exception and return
1150 Log.e(TAG, "Remote listener already died.", e);
1151 return false;
1152 }
1153
1154 return true;
1155 }
1156
1157 private class LinkedCallback implements IBinder.DeathRecipient {
1158 private final IBatchedLocationCallback mCallback;
1159
1160 public LinkedCallback(@NonNull IBatchedLocationCallback callback) {
1161 mCallback = callback;
1162 }
1163
1164 @NonNull
1165 public IBatchedLocationCallback getUnderlyingListener() {
1166 return mCallback;
1167 }
1168
1169 @Override
1170 public void binderDied() {
1171 Log.d(TAG, "Remote Batching Callback died: " + mCallback);
1172 stopGnssBatch();
1173 removeGnssBatchingCallback();
1174 }
1175 }
1176
1177 /**
1178 * Removes callback for GNSS batching
1179 */
1180 @Override
1181 public void removeGnssBatchingCallback() {
1182 try {
1183 mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
1184 0 /* flags */);
1185 } catch (NoSuchElementException e) {
1186 // if the death callback isn't connected (it should be...), log error, swallow the
1187 // exception and return
1188 Log.e(TAG, "Couldn't unlink death callback.", e);
1189 }
1190 mGnssBatchingCallback = null;
1191 mGnssBatchingDeathCallback = null;
1192 }
1193
1194
1195 /**
1196 * Starts GNSS batching, if available.
1197 */
1198 @Override
1199 public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
1200 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1201 "Location Hardware permission not granted to access hardware batching");
1202
1203 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1204 return false;
1205 }
1206
1207 if (mGnssBatchingInProgress) {
1208 // Current design does not expect multiple starts to be called repeatedly
1209 Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
1210 // Try to clean up anyway, and continue
1211 stopGnssBatch();
1212 }
1213
1214 mGnssBatchingInProgress = true;
1215 return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
1216 }
1217
1218 /**
1219 * Flushes a GNSS batch in progress
1220 */
1221 @Override
1222 public void flushGnssBatch(String packageName) {
1223 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1224 "Location Hardware permission not granted to access hardware batching");
1225
1226 if (!hasGnssPermissions(packageName)) {
1227 Log.e(TAG, "flushGnssBatch called without GNSS permissions");
1228 return;
1229 }
1230
1231 if (!mGnssBatchingInProgress) {
1232 Log.w(TAG, "flushGnssBatch called with no batch in progress");
1233 }
1234
1235 if (mGnssBatchingProvider != null) {
1236 mGnssBatchingProvider.flush();
1237 }
1238 }
1239
1240 /**
1241 * Stops GNSS batching
1242 */
1243 @Override
1244 public boolean stopGnssBatch() {
1245 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1246 "Location Hardware permission not granted to access hardware batching");
1247
1248 if (mGnssBatchingProvider != null) {
1249 mGnssBatchingInProgress = false;
1250 return mGnssBatchingProvider.stop();
1251 } else {
1252 return false;
1253 }
1254 }
1255
1256 @Override
1257 public void reportLocationBatch(List<Location> locations) {
1258 checkCallerIsProvider();
1259
1260 // Currently used only for GNSS locations - update permissions check if changed
1261 if (isAllowedByCurrentUserSettingsLocked(LocationManager.GPS_PROVIDER)) {
1262 if (mGnssBatchingCallback == null) {
1263 Slog.e(TAG, "reportLocationBatch() called without active Callback");
1264 return;
1265 }
1266 try {
1267 mGnssBatchingCallback.onLocationBatch(locations);
1268 } catch (RemoteException e) {
1269 Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
1270 }
1271 } else {
1272 Slog.w(TAG, "reportLocationBatch() called without user permission, locations blocked");
1273 }
1274 }
1275
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001276 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001277 mProviders.add(provider);
1278 mProvidersByName.put(provider.getName(), provider);
1279 }
1280
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001281 private void removeProviderLocked(LocationProviderInterface provider) {
1282 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001283 mProviders.remove(provider);
1284 mProvidersByName.remove(provider.getName());
1285 }
1286
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001287 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -08001288 * Returns "true" if access to the specified location provider is allowed by the current
1289 * user's settings. Access to all location providers is forbidden to non-location-provider
1290 * processes belonging to background users.
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001291 *
1292 * @param provider the name of the location provider
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001293 */
Victoria Lease09eeaec2013-02-05 11:34:13 -08001294 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001295 if (mEnabledProviders.contains(provider)) {
1296 return true;
1297 }
1298 if (mDisabledProviders.contains(provider)) {
1299 return false;
1300 }
1301 // Use system settings
1302 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001303
Victoria Leaseb711d572012-10-02 13:14:11 -07001304 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001305 }
1306
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001307 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -08001308 * Returns "true" if access to the specified location provider is allowed by the specified
1309 * user's settings. Access to all location providers is forbidden to non-location-provider
1310 * processes belonging to background users.
1311 *
1312 * @param provider the name of the location provider
1313 * @param uid the requestor's UID
Victoria Lease09eeaec2013-02-05 11:34:13 -08001314 */
1315 private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001316 if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001317 return false;
1318 }
1319 return isAllowedByCurrentUserSettingsLocked(provider);
1320 }
1321
1322 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001323 * Returns the permission string associated with the specified resolution level.
1324 *
1325 * @param resolutionLevel the resolution level
1326 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001327 */
Victoria Lease37425c32012-10-16 16:08:48 -07001328 private String getResolutionPermission(int resolutionLevel) {
1329 switch (resolutionLevel) {
1330 case RESOLUTION_LEVEL_FINE:
1331 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1332 case RESOLUTION_LEVEL_COARSE:
1333 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1334 default:
1335 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001336 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001337 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001338
Victoria Leaseda479c52012-10-15 15:24:16 -07001339 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001340 * Returns the resolution level allowed to the given PID/UID pair.
1341 *
1342 * @param pid the PID
1343 * @param uid the UID
1344 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -07001345 */
Victoria Lease37425c32012-10-16 16:08:48 -07001346 private int getAllowedResolutionLevel(int pid, int uid) {
1347 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
1348 pid, uid) == PackageManager.PERMISSION_GRANTED) {
1349 return RESOLUTION_LEVEL_FINE;
1350 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
1351 pid, uid) == PackageManager.PERMISSION_GRANTED) {
1352 return RESOLUTION_LEVEL_COARSE;
1353 } else {
1354 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001355 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001356 }
1357
1358 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001359 * Returns the resolution level allowed to the caller
1360 *
1361 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -07001362 */
Victoria Lease37425c32012-10-16 16:08:48 -07001363 private int getCallerAllowedResolutionLevel() {
1364 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1365 }
1366
1367 /**
1368 * Throw SecurityException if specified resolution level is insufficient to use geofences.
1369 *
1370 * @param allowedResolutionLevel resolution level allowed to caller
1371 */
1372 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1373 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001374 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1375 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001376 }
1377
Victoria Lease37425c32012-10-16 16:08:48 -07001378 /**
1379 * Return the minimum resolution level required to use the specified location provider.
1380 *
1381 * @param provider the name of the location provider
1382 * @return minimum resolution level required for provider
1383 */
1384 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001385 if (LocationManager.GPS_PROVIDER.equals(provider) ||
1386 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1387 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001388 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -07001389 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1390 LocationManager.FUSED_PROVIDER.equals(provider)) {
1391 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001392 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001393 } else {
1394 // mock providers
1395 LocationProviderInterface lp = mMockProviders.get(provider);
1396 if (lp != null) {
1397 ProviderProperties properties = lp.getProperties();
1398 if (properties != null) {
1399 if (properties.mRequiresSatellite) {
1400 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001401 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001402 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1403 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001404 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001405 }
1406 }
1407 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001408 }
Victoria Lease37425c32012-10-16 16:08:48 -07001409 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001410 }
1411
Victoria Lease37425c32012-10-16 16:08:48 -07001412 /**
1413 * Throw SecurityException if specified resolution level is insufficient to use the named
1414 * location provider.
1415 *
1416 * @param allowedResolutionLevel resolution level allowed to caller
1417 * @param providerName the name of the location provider
1418 */
1419 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1420 String providerName) {
1421 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1422 if (allowedResolutionLevel < requiredResolutionLevel) {
1423 switch (requiredResolutionLevel) {
1424 case RESOLUTION_LEVEL_FINE:
1425 throw new SecurityException("\"" + providerName + "\" location provider " +
1426 "requires ACCESS_FINE_LOCATION permission.");
1427 case RESOLUTION_LEVEL_COARSE:
1428 throw new SecurityException("\"" + providerName + "\" location provider " +
1429 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1430 default:
1431 throw new SecurityException("Insufficient permission for \"" + providerName +
1432 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001433 }
1434 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001435 }
1436
David Christie82edc9b2013-07-19 11:31:42 -07001437 /**
1438 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
1439 * for battery).
1440 */
David Christie40e57822013-07-30 11:36:48 -07001441 private void checkDeviceStatsAllowed() {
David Christie82edc9b2013-07-19 11:31:42 -07001442 mContext.enforceCallingOrSelfPermission(
1443 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
1444 }
1445
David Christie40e57822013-07-30 11:36:48 -07001446 private void checkUpdateAppOpsAllowed() {
1447 mContext.enforceCallingOrSelfPermission(
1448 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
1449 }
1450
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001451 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001452 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1453 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001454 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001455 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001456 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001457 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001458 }
1459 return -1;
1460 }
1461
David Christieb870dbf2015-06-22 12:42:53 -07001462 boolean reportLocationAccessNoThrow(
1463 int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001464 int op = resolutionLevelToOp(allowedResolutionLevel);
1465 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001466 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1467 return false;
1468 }
1469 }
David Christieb870dbf2015-06-22 12:42:53 -07001470
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001471 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001472 }
1473
David Christieb870dbf2015-06-22 12:42:53 -07001474 boolean checkLocationAccess(int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001475 int op = resolutionLevelToOp(allowedResolutionLevel);
1476 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001477 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1478 return false;
1479 }
1480 }
David Christieb870dbf2015-06-22 12:42:53 -07001481
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001482 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001483 }
1484
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001485 /**
1486 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -07001487 * fused, also including ones that are not permitted to
1488 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001489 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001490 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001491 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001492 ArrayList<String> out;
1493 synchronized (mLock) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001494 out = new ArrayList<>(mProviders.size());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001495 for (LocationProviderInterface provider : mProviders) {
1496 String name = provider.getName();
1497 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001498 continue;
1499 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001500 out.add(name);
1501 }
1502 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001503
1504 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001505 return out;
1506 }
1507
Mike Lockwood03ca2162010-04-01 08:10:09 -07001508 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001509 * Return all providers by name, that match criteria and are optionally
1510 * enabled.
1511 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001512 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001513 @Override
1514 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001515 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001516 ArrayList<String> out;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001517 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07001518 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001519 try {
1520 synchronized (mLock) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001521 out = new ArrayList<>(mProviders.size());
Victoria Leaseb711d572012-10-02 13:14:11 -07001522 for (LocationProviderInterface provider : mProviders) {
1523 String name = provider.getName();
1524 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001525 continue;
1526 }
Victoria Lease37425c32012-10-16 16:08:48 -07001527 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001528 if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001529 continue;
1530 }
1531 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
1532 name, provider.getProperties(), criteria)) {
1533 continue;
1534 }
1535 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001536 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001537 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001538 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001539 } finally {
1540 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001541 }
1542
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001543 if (D) Log.d(TAG, "getProviders()=" + out);
1544 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001545 }
1546
1547 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001548 * Return the name of the best provider given a Criteria object.
1549 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001550 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001551 * has been deprecated as well. So this method now uses
1552 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001553 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001554 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001555 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001556 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001557
1558 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001559 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001560 result = pickBest(providers);
1561 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1562 return result;
1563 }
1564 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001565 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001566 result = pickBest(providers);
1567 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1568 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001569 }
1570
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001571 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001572 return null;
1573 }
1574
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001575 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -07001576 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001577 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -07001578 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1579 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001580 } else {
1581 return providers.get(0);
1582 }
1583 }
1584
Nick Pellye0fd6932012-07-11 10:26:13 -07001585 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001586 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1587 LocationProviderInterface p = mProvidersByName.get(provider);
1588 if (p == null) {
1589 throw new IllegalArgumentException("provider=" + provider);
1590 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001591
1592 boolean result = LocationProvider.propertiesMeetCriteria(
1593 p.getName(), p.getProperties(), criteria);
1594 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1595 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001596 }
1597
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001598 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001599 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001600 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001601 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001602 boolean isEnabled = p.isEnabled();
1603 String name = p.getName();
Victoria Lease09eeaec2013-02-05 11:34:13 -08001604 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001605 if (isEnabled && !shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001606 updateProviderListenersLocked(name, false);
David Christieb084fef2013-12-18 14:33:57 -08001607 // If any provider has been disabled, clear all last locations for all providers.
1608 // This is to be on the safe side in case a provider has location derived from
1609 // this disabled provider.
1610 mLastLocation.clear();
1611 mLastLocationCoarseInterval.clear();
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001612 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613 } else if (!isEnabled && shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001614 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001615 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001616 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001617 }
1618 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001619 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1620 UserHandle.ALL);
Tom O'Neill40a86c22013-09-03 18:05:13 -07001621 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1622 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001623 }
1624 }
1625
Amith Yamasanib27528d2014-06-05 15:02:10 -07001626 private void updateProviderListenersLocked(String provider, boolean enabled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001627 int listeners = 0;
1628
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001629 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001630 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001631
1632 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001633
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001634 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1635 if (records != null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001636 for (UpdateRecord record : records) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001637 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001638 // Sends a notification message to the receiver
1639 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1640 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001641 deadReceivers = new ArrayList<>();
Victoria Leaseb711d572012-10-02 13:14:11 -07001642 }
1643 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001644 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001645 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001646 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001647 }
1648 }
1649
1650 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001651 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001652 removeUpdatesLocked(deadReceivers.get(i));
1653 }
1654 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001655
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001656 if (enabled) {
1657 p.enable();
1658 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001659 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001660 }
1661 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001662 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001663 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001664 }
1665
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001666 private void applyRequirementsLocked(String provider) {
1667 LocationProviderInterface p = mProvidersByName.get(provider);
1668 if (p == null) return;
1669
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001670 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001671 WorkSource worksource = new WorkSource();
1672 ProviderRequest providerRequest = new ProviderRequest();
1673
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001674 ContentResolver resolver = mContext.getContentResolver();
1675 long backgroundThrottleInterval = Settings.Global.getLong(
1676 resolver,
1677 Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
1678 DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
1679
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001680 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001681 for (UpdateRecord record : records) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001682 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
David Christieb870dbf2015-06-22 12:42:53 -07001683 if (checkLocationAccess(
1684 record.mReceiver.mPid,
1685 record.mReceiver.mUid,
1686 record.mReceiver.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001687 record.mReceiver.mAllowedResolutionLevel)) {
1688 LocationRequest locationRequest = record.mRequest;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001689 long interval = locationRequest.getInterval();
1690
1691 if (!isThrottlingExemptLocked(record.mReceiver)) {
1692 if (!record.mIsForegroundUid) {
1693 interval = Math.max(interval, backgroundThrottleInterval);
1694 }
1695 if (interval != locationRequest.getInterval()) {
1696 locationRequest = new LocationRequest(locationRequest);
1697 locationRequest.setInterval(interval);
1698 }
1699 }
1700
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001701 providerRequest.locationRequests.add(locationRequest);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001702 if (interval < providerRequest.interval) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001703 providerRequest.reportLocation = true;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001704 providerRequest.interval = interval;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001705 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001706 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001707 }
1708 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001709
1710 if (providerRequest.reportLocation) {
1711 // calculate who to blame for power
1712 // This is somewhat arbitrary. We pick a threshold interval
1713 // that is slightly higher that the minimum interval, and
1714 // spread the blame across all applications with a request
1715 // under that threshold.
1716 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1717 for (UpdateRecord record : records) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001718 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001719 LocationRequest locationRequest = record.mRequest;
Svet Ganove998c732016-06-10 00:12:38 -07001720
1721 // Don't assign battery blame for update records whose
1722 // client has no permission to receive location data.
1723 if (!providerRequest.locationRequests.contains(locationRequest)) {
1724 continue;
1725 }
1726
Victoria Leaseb711d572012-10-02 13:14:11 -07001727 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07001728 if (record.mReceiver.mWorkSource != null
1729 && record.mReceiver.mWorkSource.size() > 0
1730 && record.mReceiver.mWorkSource.getName(0) != null) {
David Christie82edc9b2013-07-19 11:31:42 -07001731 // Assign blame to another work source.
David Christiee55c9682013-08-22 10:10:34 -07001732 // Can only assign blame if the WorkSource contains names.
David Christie82edc9b2013-07-19 11:31:42 -07001733 worksource.add(record.mReceiver.mWorkSource);
1734 } else {
1735 // Assign blame to caller.
1736 worksource.add(
1737 record.mReceiver.mUid,
1738 record.mReceiver.mPackageName);
1739 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001740 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001741 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001742 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 }
1744 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001745
1746 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1747 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001748 }
1749
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001750 private boolean isThrottlingExemptLocked(Receiver receiver) {
1751 if (receiver.mUid == Process.SYSTEM_UID) {
1752 return true;
1753 }
1754
1755 if (receiver.mPackageName.equals(GMSCORE_PACKAGE)) {
1756 return true;
1757 }
1758
1759 for (LocationProviderProxy provider : mProxyProviders) {
1760 if (receiver.mPackageName.equals(provider.getConnectedPackageName())) {
1761 return true;
1762 }
1763 }
1764
1765 for (String whitelistedPackage : mBackgroundThrottlePackageWhitelist) {
1766 if (receiver.mPackageName.equals(whitelistedPackage)) {
1767 return true;
1768 }
1769 }
1770
1771 return false;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001772 }
1773
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001774 private class UpdateRecord {
1775 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001776 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001777 final Receiver mReceiver;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001778 boolean mIsForegroundUid;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001779 Location mLastFixBroadcast;
1780 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001781
1782 /**
1783 * Note: must be constructed with lock held.
1784 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001785 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001786 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001787 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001788 mReceiver = receiver;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001789 mIsForegroundUid = isImportanceForeground(
1790 mActivityManager.getPackageImportance(mReceiver.mPackageName));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001791
1792 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1793 if (records == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001794 records = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001795 mRecordsByProvider.put(provider, records);
1796 }
1797 if (!records.contains(this)) {
1798 records.add(this);
1799 }
David Christie2ff96af2014-01-30 16:09:37 -08001800
1801 // Update statistics for historical location requests by package/provider
1802 mRequestStatistics.startRequesting(
1803 mReceiver.mPackageName, provider, request.getInterval());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804 }
1805
1806 /**
David Christie2ff96af2014-01-30 16:09:37 -08001807 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001808 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001809 void disposeLocked(boolean removeReceiver) {
David Christie2ff96af2014-01-30 16:09:37 -08001810 mRequestStatistics.stopRequesting(mReceiver.mPackageName, mProvider);
1811
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001812 // remove from mRecordsByProvider
1813 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1814 if (globalRecords != null) {
1815 globalRecords.remove(this);
1816 }
1817
1818 if (!removeReceiver) return; // the caller will handle the rest
1819
1820 // remove from Receiver#mUpdateRecords
1821 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1822 if (receiverRecords != null) {
1823 receiverRecords.remove(this.mProvider);
1824
1825 // and also remove the Receiver if it has no more update records
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001826 if (receiverRecords.size() == 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001827 removeUpdatesLocked(mReceiver);
1828 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001829 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001830 }
1831
1832 @Override
1833 public String toString() {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001834 return "UpdateRecord[" + mProvider + " " + mReceiver.mPackageName
1835 + "(" + mReceiver.mUid + (mIsForegroundUid ? " foreground" : " background")
1836 + ")" + " " + mRequest + "]";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001837 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001838 }
1839
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001840 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07001841 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001842 IBinder binder = listener.asBinder();
1843 Receiver receiver = mReceivers.get(binder);
1844 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001845 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
1846 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001847 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001848 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001849 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001850 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001851 return null;
1852 }
Wen Jingcb3ab222014-03-27 13:42:59 +08001853 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001854 }
1855 return receiver;
1856 }
1857
David Christie82edc9b2013-07-19 11:31:42 -07001858 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07001859 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001860 Receiver receiver = mReceivers.get(intent);
1861 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001862 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
1863 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001864 mReceivers.put(intent, receiver);
1865 }
1866 return receiver;
1867 }
1868
Victoria Lease37425c32012-10-16 16:08:48 -07001869 /**
1870 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1871 * and consistency requirements.
1872 *
1873 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07001874 * @return a version of request that meets the given resolution and consistency requirements
1875 * @hide
1876 */
1877 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1878 LocationRequest sanitizedRequest = new LocationRequest(request);
1879 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1880 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001881 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001882 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001883 break;
1884 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001885 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001886 break;
1887 }
1888 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001889 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1890 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001891 }
Victoria Lease37425c32012-10-16 16:08:48 -07001892 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1893 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001894 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001895 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001896 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001897 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001898 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001899 }
Victoria Lease37425c32012-10-16 16:08:48 -07001900 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001901 }
1902
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001903 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001904 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001905 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001906 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001907 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001908 String[] packages = mPackageManager.getPackagesForUid(uid);
1909 if (packages == null) {
1910 throw new SecurityException("invalid UID " + uid);
1911 }
1912 for (String pkg : packages) {
1913 if (packageName.equals(pkg)) return;
1914 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001915 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001916 }
1917
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001918 private void checkPendingIntent(PendingIntent intent) {
1919 if (intent == null) {
1920 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001921 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001922 }
1923
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001924 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
David Christie40e57822013-07-30 11:36:48 -07001925 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001926 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001927 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001928 } else if (intent != null && listener != null) {
1929 throw new IllegalArgumentException("cannot register both listener and intent");
1930 } else if (intent != null) {
1931 checkPendingIntent(intent);
David Christie40e57822013-07-30 11:36:48 -07001932 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001933 } else {
David Christie40e57822013-07-30 11:36:48 -07001934 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001935 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001936 }
1937
Nick Pellye0fd6932012-07-11 10:26:13 -07001938 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001939 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1940 PendingIntent intent, String packageName) {
1941 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1942 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001943 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1944 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1945 request.getProvider());
David Christie82edc9b2013-07-19 11:31:42 -07001946 WorkSource workSource = request.getWorkSource();
1947 if (workSource != null && workSource.size() > 0) {
David Christie40e57822013-07-30 11:36:48 -07001948 checkDeviceStatsAllowed();
1949 }
1950 boolean hideFromAppOps = request.getHideFromAppOps();
1951 if (hideFromAppOps) {
1952 checkUpdateAppOpsAllowed();
David Christie82edc9b2013-07-19 11:31:42 -07001953 }
Victoria Lease37425c32012-10-16 16:08:48 -07001954 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001955
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001956 final int pid = Binder.getCallingPid();
1957 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001958 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001959 long identity = Binder.clearCallingIdentity();
1960 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001961 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1962 // a location.
David Christieb870dbf2015-06-22 12:42:53 -07001963 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001964
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001965 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001966 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
David Christie40e57822013-07-30 11:36:48 -07001967 packageName, workSource, hideFromAppOps);
Victoria Lease37425c32012-10-16 16:08:48 -07001968 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001969 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001970 } finally {
1971 Binder.restoreCallingIdentity(identity);
1972 }
1973 }
1974
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001975 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1976 int pid, int uid, String packageName) {
1977 // Figure out the provider. Either its explicitly request (legacy use cases), or
1978 // use the fused provider
1979 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1980 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001981 if (name == null) {
1982 throw new IllegalArgumentException("provider name must not be null");
1983 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07001984
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001985 LocationProviderInterface provider = mProvidersByName.get(name);
1986 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07001987 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001988 }
1989
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001990 UpdateRecord record = new UpdateRecord(name, request, receiver);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001991 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1992 + " " + name + " " + request + " from " + packageName + "(" + uid + " "
1993 + (record.mIsForegroundUid ? "foreground" : "background")
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001994 + (isThrottlingExemptLocked(receiver) ? " [whitelisted]" : "") + ")");
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001995
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001996 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1997 if (oldRecord != null) {
1998 oldRecord.disposeLocked(false);
1999 }
2000
Victoria Lease09eeaec2013-02-05 11:34:13 -08002001 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002002 if (isProviderEnabled) {
2003 applyRequirementsLocked(name);
2004 } else {
2005 // Notify the listener that updates are currently disabled
2006 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002007 }
David Christie0b837452013-07-29 16:02:13 -07002008 // Update the monitoring here just in case multiple location requests were added to the
2009 // same receiver (this request may be high power and the initial might not have been).
2010 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002011 }
2012
Nick Pellye0fd6932012-07-11 10:26:13 -07002013 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002014 public void removeUpdates(ILocationListener listener, PendingIntent intent,
2015 String packageName) {
2016 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002017
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002018 final int pid = Binder.getCallingPid();
2019 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002020
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002021 synchronized (mLock) {
David Christie82edc9b2013-07-19 11:31:42 -07002022 WorkSource workSource = null;
David Christie40e57822013-07-30 11:36:48 -07002023 boolean hideFromAppOps = false;
2024 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
2025 packageName, workSource, hideFromAppOps);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002026
2027 // providers may use public location API's, need to clear identity
2028 long identity = Binder.clearCallingIdentity();
2029 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002030 removeUpdatesLocked(receiver);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002031 } finally {
2032 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002033 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002034 }
2035 }
2036
2037 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08002038 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002039
2040 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
2041 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
2042 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07002043 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002044 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002045 }
2046
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07002047 receiver.updateMonitoring(false);
2048
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002049 // Record which providers were associated with this listener
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002050 HashSet<String> providers = new HashSet<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002051 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
2052 if (oldRecords != null) {
2053 // Call dispose() on the obsolete update records.
2054 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08002055 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002056 record.disposeLocked(false);
2057 }
2058 // Accumulate providers
2059 providers.addAll(oldRecords.keySet());
2060 }
2061
2062 // update provider
2063 for (String provider : providers) {
2064 // If provider is already disabled, don't need to do anything
Victoria Lease09eeaec2013-02-05 11:34:13 -08002065 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002066 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002067 }
2068
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002069 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002070 }
2071 }
2072
Dianne Hackbornc2293022013-02-06 23:14:49 -08002073 private void applyAllProviderRequirementsLocked() {
2074 for (LocationProviderInterface p : mProviders) {
2075 // If provider is already disabled, don't need to do anything
Dianne Hackborn64d41d72013-02-07 00:33:31 -08002076 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08002077 continue;
2078 }
2079
2080 applyRequirementsLocked(p.getName());
2081 }
2082 }
2083
Nick Pellye0fd6932012-07-11 10:26:13 -07002084 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07002085 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002086 if (D) Log.d(TAG, "getLastLocation: " + request);
2087 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002088 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07002089 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002090 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2091 request.getProvider());
2092 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07002093
David Christieb870dbf2015-06-22 12:42:53 -07002094 final int pid = Binder.getCallingPid();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002095 final int uid = Binder.getCallingUid();
2096 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07002097 try {
2098 if (mBlacklist.isBlacklisted(packageName)) {
2099 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
2100 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07002101 return null;
2102 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002103
David Christieb870dbf2015-06-22 12:42:53 -07002104 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002105 if (D) Log.d(TAG, "not returning last loc for no op app: " +
2106 packageName);
2107 return null;
2108 }
2109
Victoria Leaseb711d572012-10-02 13:14:11 -07002110 synchronized (mLock) {
2111 // Figure out the provider. Either its explicitly request (deprecated API's),
2112 // or use the fused provider
2113 String name = request.getProvider();
2114 if (name == null) name = LocationManager.FUSED_PROVIDER;
2115 LocationProviderInterface provider = mProvidersByName.get(name);
2116 if (provider == null) return null;
2117
Victoria Lease09eeaec2013-02-05 11:34:13 -08002118 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07002119
David Christie1b9b7b12013-04-15 15:31:11 -07002120 Location location;
2121 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2122 // Make sure that an app with coarse permissions can't get frequent location
2123 // updates by calling LocationManager.getLastKnownLocation repeatedly.
2124 location = mLastLocationCoarseInterval.get(name);
2125 } else {
2126 location = mLastLocation.get(name);
2127 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002128 if (location == null) {
2129 return null;
2130 }
Victoria Lease37425c32012-10-16 16:08:48 -07002131 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07002132 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2133 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08002134 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07002135 }
Victoria Lease37425c32012-10-16 16:08:48 -07002136 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08002137 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07002138 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002139 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002140 return null;
2141 } finally {
2142 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002143 }
2144 }
2145
2146 @Override
2147 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
2148 String packageName) {
2149 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002150 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2151 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002152 checkPendingIntent(intent);
2153 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002154 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2155 request.getProvider());
2156 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002157
Victoria Lease37425c32012-10-16 16:08:48 -07002158 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002159
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002160 // geo-fence manager uses the public location API, need to clear identity
2161 int uid = Binder.getCallingUid();
Xiaohui Chena4490622015-09-22 15:29:31 -07002162 // TODO: http://b/23822629
2163 if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
Victoria Lease56e675b2012-11-05 19:25:06 -08002164 // temporary measure until geofences work for secondary users
2165 Log.w(TAG, "proximity alerts are currently available only to the primary user");
2166 return;
2167 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002168 long identity = Binder.clearCallingIdentity();
2169 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002170 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
2171 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002172 } finally {
2173 Binder.restoreCallingIdentity(identity);
2174 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002175 }
2176
2177 @Override
2178 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002179 checkPendingIntent(intent);
2180 checkPackageName(packageName);
2181
2182 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
2183
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002184 // geo-fence manager uses the public location API, need to clear identity
2185 long identity = Binder.clearCallingIdentity();
2186 try {
2187 mGeofenceManager.removeFence(geofence, intent);
2188 } finally {
2189 Binder.restoreCallingIdentity(identity);
2190 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002191 }
2192
2193
2194 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002195 public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002196 if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09002197 return false;
2198 }
2199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002200 try {
Lifu Tang30f95a72016-01-07 23:20:38 -08002201 mGnssStatusProvider.registerGnssStatusCallback(callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002202 } catch (RemoteException e) {
Lifu Tang30f95a72016-01-07 23:20:38 -08002203 Slog.e(TAG, "mGpsStatusProvider.registerGnssStatusCallback failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002204 return false;
2205 }
2206 return true;
2207 }
2208
Nick Pellye0fd6932012-07-11 10:26:13 -07002209 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002210 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002211 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002212 try {
Lifu Tang30f95a72016-01-07 23:20:38 -08002213 mGnssStatusProvider.unregisterGnssStatusCallback(callback);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002214 } catch (Exception e) {
Lifu Tang30f95a72016-01-07 23:20:38 -08002215 Slog.e(TAG, "mGpsStatusProvider.unregisterGnssStatusCallback failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002216 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002217 }
2218 }
2219
Nick Pellye0fd6932012-07-11 10:26:13 -07002220 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002221 public boolean addGnssMeasurementsListener(
2222 IGnssMeasurementsListener listener,
destradaaea8a8a62014-06-23 18:19:03 -07002223 String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002224 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07002225 return false;
2226 }
Lifu Tang818aa2c2016-02-01 01:52:00 -08002227 return mGnssMeasurementsProvider.addListener(listener);
destradaaea8a8a62014-06-23 18:19:03 -07002228 }
2229
2230 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002231 public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
2232 if (mGnssMeasurementsProvider != null) {
2233 mGnssMeasurementsProvider.removeListener(listener);
Wei Liu5241a4c2015-05-11 14:00:36 -07002234 }
destradaaea8a8a62014-06-23 18:19:03 -07002235 }
2236
2237 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002238 public boolean addGnssNavigationMessageListener(
2239 IGnssNavigationMessageListener listener,
destradaa4b3e3932014-07-21 18:01:47 -07002240 String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002241 if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07002242 return false;
2243 }
Lifu Tang818aa2c2016-02-01 01:52:00 -08002244 return mGnssNavigationMessageProvider.addListener(listener);
destradaa4b3e3932014-07-21 18:01:47 -07002245 }
2246
2247 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002248 public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
2249 if (mGnssNavigationMessageProvider != null) {
2250 mGnssNavigationMessageProvider.removeListener(listener);
Wei Liu5241a4c2015-05-11 14:00:36 -07002251 }
destradaa4b3e3932014-07-21 18:01:47 -07002252 }
2253
2254 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002255 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002256 if (provider == null) {
2257 // throw NullPointerException to remain compatible with previous implementation
2258 throw new NullPointerException();
2259 }
Victoria Lease37425c32012-10-16 16:08:48 -07002260 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2261 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002263 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04002264 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002265 != PackageManager.PERMISSION_GRANTED)) {
2266 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2267 }
2268
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002269 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002270 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002271 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07002272
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002273 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002274 }
2275 }
2276
Nick Pellye0fd6932012-07-11 10:26:13 -07002277 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002278 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07002279 if (Binder.getCallingUid() != Process.myUid()) {
2280 throw new SecurityException(
2281 "calling sendNiResponse from outside of the system is not allowed");
2282 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04002283 try {
2284 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002285 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002286 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04002287 return false;
2288 }
2289 }
2290
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002291 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002292 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11002293 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002294 * accessed by the caller
2295 */
Nick Pellye0fd6932012-07-11 10:26:13 -07002296 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002297 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07002298 if (mProvidersByName.get(provider) == null) {
David Christie2ff96af2014-01-30 16:09:37 -08002299 return null;
Laurent Tub7f9d252012-10-16 14:25:00 -07002300 }
2301
Victoria Lease37425c32012-10-16 16:08:48 -07002302 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2303 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002304
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002305 LocationProviderInterface p;
2306 synchronized (mLock) {
2307 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002308 }
2309
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002310 if (p == null) return null;
2311 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002312 }
2313
Jason Monkb71218a2015-06-17 14:44:39 -04002314 /**
2315 * @return null if the provider does not exist
2316 * @throws SecurityException if the provider is not allowed to be
2317 * accessed by the caller
2318 */
2319 @Override
2320 public String getNetworkProviderPackage() {
2321 LocationProviderInterface p;
2322 synchronized (mLock) {
2323 if (mProvidersByName.get(LocationManager.NETWORK_PROVIDER) == null) {
2324 return null;
2325 }
2326 p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
2327 }
2328
2329 if (p instanceof LocationProviderProxy) {
2330 return ((LocationProviderProxy) p).getConnectedPackageName();
2331 }
2332 return null;
2333 }
2334
Nick Pellye0fd6932012-07-11 10:26:13 -07002335 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002336 public boolean isProviderEnabled(String provider) {
Tom O'Neilld5759432013-09-11 11:03:03 -07002337 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2338 // so we discourage its use
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002339 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
2340
Victoria Lease09eeaec2013-02-05 11:34:13 -08002341 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07002342 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07002343 try {
2344 synchronized (mLock) {
2345 LocationProviderInterface p = mProvidersByName.get(provider);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002346 return p != null && isAllowedByUserSettingsLocked(provider, uid);
Victoria Leaseb711d572012-10-02 13:14:11 -07002347 }
2348 } finally {
2349 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002350 }
2351 }
2352
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002353 /**
2354 * Returns "true" if the UID belongs to a bound location provider.
2355 *
2356 * @param uid the uid
2357 * @return true if uid belongs to a bound location provider
2358 */
2359 private boolean isUidALocationProvider(int uid) {
2360 if (uid == Process.SYSTEM_UID) {
2361 return true;
2362 }
2363 if (mGeocodeProvider != null) {
David Christie1f141c12014-05-14 15:11:15 -07002364 if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002365 }
2366 for (LocationProviderProxy proxy : mProxyProviders) {
David Christie1f141c12014-05-14 15:11:15 -07002367 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002368 }
2369 return false;
2370 }
2371
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002372 private void checkCallerIsProvider() {
2373 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
2374 == PackageManager.PERMISSION_GRANTED) {
2375 return;
2376 }
2377
2378 // Previously we only used the INSTALL_LOCATION_PROVIDER
2379 // check. But that is system or signature
2380 // protection level which is not flexible enough for
2381 // providers installed oustide the system image. So
2382 // also allow providers with a UID matching the
2383 // currently bound package name
2384
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002385 if (isUidALocationProvider(Binder.getCallingUid())) {
2386 return;
2387 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002388
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002389 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2390 "or UID of a currently bound location provider");
2391 }
2392
David Christie1f141c12014-05-14 15:11:15 -07002393 /**
2394 * Returns true if the given package belongs to the given uid.
2395 */
2396 private boolean doesUidHavePackage(int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002397 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002398 return false;
2399 }
David Christie1f141c12014-05-14 15:11:15 -07002400 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2401 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002402 return false;
2403 }
David Christie1f141c12014-05-14 15:11:15 -07002404 for (String name : packageNames) {
2405 if (packageName.equals(name)) {
2406 return true;
2407 }
2408 }
2409 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002410 }
2411
Nick Pellye0fd6932012-07-11 10:26:13 -07002412 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05002413 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002414 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04002415
Nick Pelly2eeeec22012-07-18 13:13:37 -07002416 if (!location.isComplete()) {
2417 Log.w(TAG, "Dropping incomplete location: " + location);
2418 return;
2419 }
2420
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002421 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2422 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05002423 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002424 mLocationHandler.sendMessageAtFrontOfQueue(m);
2425 }
2426
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002427
Laurent Tu75defb62012-11-01 16:21:52 -07002428 private static boolean shouldBroadcastSafe(
2429 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002430 // Always broadcast the first update
2431 if (lastLoc == null) {
2432 return true;
2433 }
2434
Nick Pellyf1be6862012-05-15 10:53:42 -07002435 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002436 long minTime = record.mRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002437 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2438 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002439 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002440 return false;
2441 }
2442
2443 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002444 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002445 if (minDistance > 0.0) {
2446 if (loc.distanceTo(lastLoc) <= minDistance) {
2447 return false;
2448 }
2449 }
2450
Laurent Tu75defb62012-11-01 16:21:52 -07002451 // Check whether sufficient number of udpates is left
2452 if (record.mRequest.getNumUpdates() <= 0) {
2453 return false;
2454 }
2455
2456 // Check whether the expiry date has passed
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002457 return record.mRequest.getExpireAt() >= now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002458 }
2459
Mike Lockwooda4903f22010-02-17 06:42:23 -05002460 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002461 if (D) Log.d(TAG, "incoming location: " + location);
2462
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002463 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05002464 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002465
Laurent Tu60ec50a2012-10-04 17:00:10 -07002466 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002467 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002468 if (p == null) return;
2469
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002470 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07002471 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002472 Location lastNoGPSLocation;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002473 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002474 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002475 lastLocation = new Location(provider);
2476 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07002477 } else {
2478 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2479 if (noGPSLocation == null && lastNoGPSLocation != null) {
2480 // New location has no no-GPS location: adopt last no-GPS location. This is set
2481 // directly into location because we do not want to notify COARSE clients.
2482 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
2483 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07002484 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002485 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002486
David Christie1b9b7b12013-04-15 15:31:11 -07002487 // Update last known coarse interval location if enough time has passed.
2488 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2489 if (lastLocationCoarseInterval == null) {
2490 lastLocationCoarseInterval = new Location(location);
2491 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2492 }
2493 long timeDiffNanos = location.getElapsedRealtimeNanos()
2494 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2495 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
2496 lastLocationCoarseInterval.set(location);
2497 }
2498 // Don't ever return a coarse location that is more recent than the allowed update
2499 // interval (i.e. don't allow an app to keep registering and unregistering for
2500 // location updates to overcome the minimum interval).
2501 noGPSLocation =
2502 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2503
Laurent Tu60ec50a2012-10-04 17:00:10 -07002504 // Skip if there are no UpdateRecords for this provider.
2505 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2506 if (records == null || records.size() == 0) return;
2507
Victoria Lease09016ab2012-09-16 12:33:15 -07002508 // Fetch coarse location
2509 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07002510 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002511 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2512 }
2513
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002514 // Fetch latest status update time
2515 long newStatusUpdateTime = p.getStatusUpdateTime();
2516
David Christie2ff96af2014-01-30 16:09:37 -08002517 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002518 Bundle extras = new Bundle();
2519 int status = p.getStatus(extras);
2520
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002521 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002522 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07002523
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002524 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002525 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002526 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07002527 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07002528
Victoria Lease269518e2012-10-29 08:25:39 -07002529 int receiverUserId = UserHandle.getUserId(receiver.mUid);
Amith Yamasanib27528d2014-06-05 15:02:10 -07002530 if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07002531 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07002532 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07002533 " (current user: " + mCurrentUserId + ", app: " +
2534 receiver.mPackageName + ")");
2535 }
2536 continue;
2537 }
2538
Nick Pelly4035f5a2012-08-17 14:43:49 -07002539 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
2540 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
2541 receiver.mPackageName);
2542 continue;
2543 }
2544
David Christieb870dbf2015-06-22 12:42:53 -07002545 if (!reportLocationAccessNoThrow(receiver.mPid, receiver.mUid, receiver.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002546 receiver.mAllowedResolutionLevel)) {
2547 if (D) Log.d(TAG, "skipping loc update for no op app: " +
2548 receiver.mPackageName);
2549 continue;
2550 }
2551
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002552 Location notifyLocation;
Victoria Lease37425c32012-10-16 16:08:48 -07002553 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2554 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002555 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07002556 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002557 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002558 if (notifyLocation != null) {
2559 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07002560 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002561 if (lastLoc == null) {
2562 lastLoc = new Location(notifyLocation);
2563 r.mLastFixBroadcast = lastLoc;
2564 } else {
2565 lastLoc.set(notifyLocation);
2566 }
2567 if (!receiver.callLocationChangedLocked(notifyLocation)) {
2568 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2569 receiverDead = true;
2570 }
Laurent Tu75defb62012-11-01 16:21:52 -07002571 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002572 }
2573 }
2574
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002575 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002576 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07002577 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002578
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002579 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002580 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002581 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08002582 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07002583 }
2584 }
2585
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002586 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07002587 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002588 if (deadUpdateRecords == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002589 deadUpdateRecords = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002590 }
2591 deadUpdateRecords.add(r);
2592 }
2593 // track dead receivers
2594 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002595 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002596 deadReceivers = new ArrayList<>();
Mike Lockwood03ca2162010-04-01 08:10:09 -07002597 }
2598 if (!deadReceivers.contains(receiver)) {
2599 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002600 }
2601 }
2602 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002603
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002604 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002605 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002606 for (Receiver receiver : deadReceivers) {
2607 removeUpdatesLocked(receiver);
2608 }
2609 }
2610 if (deadUpdateRecords != null) {
2611 for (UpdateRecord r : deadUpdateRecords) {
2612 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002613 }
Victoria Lease8b38b292012-12-04 15:04:43 -08002614 applyRequirementsLocked(provider);
2615 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002616 }
2617
2618 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08002619 public LocationWorkerHandler(Looper looper) {
2620 super(looper, null, true);
2621 }
2622
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002623 @Override
2624 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002625 switch (msg.what) {
2626 case MSG_LOCATION_CHANGED:
2627 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
2628 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002629 }
2630 }
2631 }
2632
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002633 private boolean isMockProvider(String provider) {
2634 synchronized (mLock) {
2635 return mMockProviders.containsKey(provider);
2636 }
2637 }
2638
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002639 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002640 // create a working copy of the incoming Location so that the service can modify it without
2641 // disturbing the caller's copy
2642 Location myLocation = new Location(location);
2643 String provider = myLocation.getProvider();
2644
2645 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2646 // bit if location did not come from a mock provider because passive/fused providers can
2647 // forward locations from mock providers, and should not grant them legitimacy in doing so.
2648 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
2649 myLocation.setIsFromMockProvider(true);
2650 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08002651
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002652 synchronized (mLock) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08002653 if (isAllowedByCurrentUserSettingsLocked(provider)) {
2654 if (!passive) {
2655 // notify passive provider of the new location
2656 mPassiveProvider.updateLocation(myLocation);
2657 }
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002658 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002660 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002661 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002662
Mike Lockwoode97ae402010-09-29 15:23:46 -04002663 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2664 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002665 public void onPackageDisappeared(String packageName, int reason) {
2666 // remove all receivers associated with this package name
2667 synchronized (mLock) {
2668 ArrayList<Receiver> deadReceivers = null;
2669
2670 for (Receiver receiver : mReceivers.values()) {
2671 if (receiver.mPackageName.equals(packageName)) {
2672 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002673 deadReceivers = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002674 }
2675 deadReceivers.add(receiver);
2676 }
2677 }
2678
2679 // perform removal outside of mReceivers loop
2680 if (deadReceivers != null) {
2681 for (Receiver receiver : deadReceivers) {
2682 removeUpdatesLocked(receiver);
2683 }
2684 }
2685 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002686 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04002687 };
2688
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002689 // Geocoder
2690
Nick Pellye0fd6932012-07-11 10:26:13 -07002691 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04002692 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07002693 return mGeocodeProvider != null;
2694 }
2695
Nick Pellye0fd6932012-07-11 10:26:13 -07002696 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002697 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002698 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002699 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002700 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2701 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002702 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002703 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002704 }
2705
Mike Lockwooda55c3212009-04-15 11:10:11 -04002706
Nick Pellye0fd6932012-07-11 10:26:13 -07002707 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002708 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04002709 double lowerLeftLatitude, double lowerLeftLongitude,
2710 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002711 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002712
2713 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002714 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2715 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2716 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002717 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002718 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002719 }
2720
2721 // Mock Providers
2722
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002723 private boolean canCallerAccessMockLocation(String opPackageName) {
2724 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
2725 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002726 }
2727
Nick Pellye0fd6932012-07-11 10:26:13 -07002728 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002729 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
2730 if (!canCallerAccessMockLocation(opPackageName)) {
2731 return;
2732 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002733
Mike Lockwooda4903f22010-02-17 06:42:23 -05002734 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2735 throw new IllegalArgumentException("Cannot mock the passive location provider");
2736 }
2737
Mike Lockwood86328a92009-10-23 08:38:25 -04002738 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002739 synchronized (mLock) {
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002740 // remove the real provider if we are replacing GPS or network provider
2741 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07002742 || LocationManager.NETWORK_PROVIDER.equals(name)
2743 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002744 LocationProviderInterface p = mProvidersByName.get(name);
2745 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002746 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002747 }
2748 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09002749 addTestProviderLocked(name, properties);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002750 updateProvidersLocked();
2751 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002752 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002753 }
2754
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09002755 private void addTestProviderLocked(String name, ProviderProperties properties) {
2756 if (mProvidersByName.get(name) != null) {
2757 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2758 }
2759 MockProvider provider = new MockProvider(name, this, properties);
2760 addProviderLocked(provider);
2761 mMockProviders.put(name, provider);
2762 mLastLocation.put(name, null);
2763 mLastLocationCoarseInterval.put(name, null);
2764 }
2765
Nick Pellye0fd6932012-07-11 10:26:13 -07002766 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002767 public void removeTestProvider(String provider, String opPackageName) {
2768 if (!canCallerAccessMockLocation(opPackageName)) {
2769 return;
2770 }
2771
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002772 synchronized (mLock) {
Tom O'Neill07ee5d12014-03-03 17:48:35 -08002773
2774 // These methods can't be called after removing the test provider, so first make sure
Tom O'Neillfe6d3c52014-03-04 08:26:17 -08002775 // we don't leave anything dangling.
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002776 clearTestProviderEnabled(provider, opPackageName);
2777 clearTestProviderLocation(provider, opPackageName);
2778 clearTestProviderStatus(provider, opPackageName);
Tom O'Neill07ee5d12014-03-03 17:48:35 -08002779
You Kima6d0b6f2012-10-28 03:58:44 +09002780 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002781 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002782 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2783 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002784 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002785 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002786
2787 // reinstate real provider if available
2788 LocationProviderInterface realProvider = mRealProviders.get(provider);
2789 if (realProvider != null) {
2790 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002791 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002792 mLastLocation.put(provider, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002793 mLastLocationCoarseInterval.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002794 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002795 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002796 }
2797 }
2798
Nick Pellye0fd6932012-07-11 10:26:13 -07002799 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002800 public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
2801 if (!canCallerAccessMockLocation(opPackageName)) {
2802 return;
2803 }
2804
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002805 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002806 MockProvider mockProvider = mMockProviders.get(provider);
2807 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002808 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2809 }
Tom O'Neilla206a0f2016-12-15 10:26:28 -08002810
2811 // Ensure that the location is marked as being mock. There's some logic to do this in
2812 // handleLocationChanged(), but it fails if loc has the wrong provider (bug 33091107).
2813 Location mock = new Location(loc);
2814 mock.setIsFromMockProvider(true);
2815
2816 if (!TextUtils.isEmpty(loc.getProvider()) && !provider.equals(loc.getProvider())) {
2817 // The location has an explicit provider that is different from the mock provider
2818 // name. The caller may be trying to fool us via bug 33091107.
2819 EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
2820 provider + "!=" + loc.getProvider());
2821 }
2822
Mike Lockwood95427cd2009-05-07 13:27:54 -04002823 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2824 long identity = Binder.clearCallingIdentity();
Tom O'Neilla206a0f2016-12-15 10:26:28 -08002825 mockProvider.setLocation(mock);
Mike Lockwood95427cd2009-05-07 13:27:54 -04002826 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002827 }
2828 }
2829
Nick Pellye0fd6932012-07-11 10:26:13 -07002830 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002831 public void clearTestProviderLocation(String provider, String opPackageName) {
2832 if (!canCallerAccessMockLocation(opPackageName)) {
2833 return;
2834 }
2835
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002836 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002837 MockProvider mockProvider = mMockProviders.get(provider);
2838 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002839 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2840 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002841 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002842 }
2843 }
2844
Nick Pellye0fd6932012-07-11 10:26:13 -07002845 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002846 public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
2847 if (!canCallerAccessMockLocation(opPackageName)) {
2848 return;
2849 }
2850
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002851 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002852 MockProvider mockProvider = mMockProviders.get(provider);
2853 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002854 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2855 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002856 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002857 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002858 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002859 mEnabledProviders.add(provider);
2860 mDisabledProviders.remove(provider);
2861 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002862 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002863 mEnabledProviders.remove(provider);
2864 mDisabledProviders.add(provider);
2865 }
2866 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002867 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002868 }
2869 }
2870
Nick Pellye0fd6932012-07-11 10:26:13 -07002871 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002872 public void clearTestProviderEnabled(String provider, String opPackageName) {
2873 if (!canCallerAccessMockLocation(opPackageName)) {
2874 return;
2875 }
2876
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002877 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002878 MockProvider mockProvider = mMockProviders.get(provider);
2879 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002880 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2881 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002882 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002883 mEnabledProviders.remove(provider);
2884 mDisabledProviders.remove(provider);
2885 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002886 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002887 }
2888 }
2889
Nick Pellye0fd6932012-07-11 10:26:13 -07002890 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002891 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
2892 String opPackageName) {
2893 if (!canCallerAccessMockLocation(opPackageName)) {
2894 return;
2895 }
2896
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002897 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002898 MockProvider mockProvider = mMockProviders.get(provider);
2899 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002900 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2901 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002902 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002903 }
2904 }
2905
Nick Pellye0fd6932012-07-11 10:26:13 -07002906 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002907 public void clearTestProviderStatus(String provider, String opPackageName) {
2908 if (!canCallerAccessMockLocation(opPackageName)) {
2909 return;
2910 }
2911
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002912 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002913 MockProvider mockProvider = mMockProviders.get(provider);
2914 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002915 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2916 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002917 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002918 }
2919 }
2920
2921 private void log(String log) {
2922 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002923 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002924 }
2925 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002926
2927 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002928 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2929 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2930 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002931 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002932 + Binder.getCallingPid()
2933 + ", uid=" + Binder.getCallingUid());
2934 return;
2935 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002936
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002937 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002938 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002939 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002940 for (Receiver receiver : mReceivers.values()) {
2941 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002942 }
David Christie2ff96af2014-01-30 16:09:37 -08002943 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002944 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2945 pw.println(" " + entry.getKey() + ":");
2946 for (UpdateRecord record : entry.getValue()) {
2947 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002948 }
2949 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002950 pw.println(" Overlay Provider Packages:");
2951 for (LocationProviderInterface provider : mProviders) {
2952 if (provider instanceof LocationProviderProxy) {
2953 pw.println(" " + provider.getName() + ": "
2954 + ((LocationProviderProxy) provider).getConnectedPackageName());
2955 }
2956 }
David Christie2ff96af2014-01-30 16:09:37 -08002957 pw.println(" Historical Records by Provider:");
2958 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
2959 : mRequestStatistics.statistics.entrySet()) {
2960 PackageProviderKey key = entry.getKey();
2961 PackageStatistics stats = entry.getValue();
2962 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
2963 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002964 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002965 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2966 String provider = entry.getKey();
2967 Location location = entry.getValue();
2968 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002969 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002970
David Christie1b9b7b12013-04-15 15:31:11 -07002971 pw.println(" Last Known Locations Coarse Intervals:");
2972 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2973 String provider = entry.getKey();
2974 Location location = entry.getValue();
2975 pw.println(" " + provider + ": " + location);
2976 }
2977
Nick Pellye0fd6932012-07-11 10:26:13 -07002978 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002979
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002980 if (mEnabledProviders.size() > 0) {
2981 pw.println(" Enabled Providers:");
2982 for (String i : mEnabledProviders) {
2983 pw.println(" " + i);
2984 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002985
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002986 }
2987 if (mDisabledProviders.size() > 0) {
2988 pw.println(" Disabled Providers:");
2989 for (String i : mDisabledProviders) {
2990 pw.println(" " + i);
2991 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002992 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002993 pw.append(" ");
2994 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002995 if (mMockProviders.size() > 0) {
2996 pw.println(" Mock Providers:");
2997 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002998 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002999 }
3000 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003001
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003002 pw.append(" fudger: ");
3003 mLocationFudger.dump(fd, pw, args);
3004
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003005 if (args.length > 0 && "short".equals(args[0])) {
3006 return;
3007 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003008 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003009 pw.print(provider.getName() + " Internal State");
3010 if (provider instanceof LocationProviderProxy) {
3011 LocationProviderProxy proxy = (LocationProviderProxy) provider;
3012 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003013 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003014 pw.println(":");
3015 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003016 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08003017 if (mGnssBatchingInProgress) {
3018 pw.println(" GNSS batching in progress");
3019 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003020 }
3021 }
3022}