blob: 9dbfe5fb9df0dd5db6b4abfa0d3daad81f3f7a0c [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Maggieaa080f92018-01-04 15:35:11 -080019import static android.content.pm.PackageManager.PERMISSION_GRANTED;
Soonil Nagarkar1575a042018-10-24 17:54:54 -070020import static android.location.LocationProvider.AVAILABLE;
Soonil Nagarkar94749f72018-11-08 11:46:43 -080021import static android.provider.Settings.Global.LOCATION_DISABLE_STATUS_CALLBACKS;
Maggieaa080f92018-01-04 15:35:11 -080022
Soonil Nagarkar1575a042018-10-24 17:54:54 -070023import static com.android.internal.util.Preconditions.checkState;
24
Wei Wang980b7c22018-12-06 17:53:00 -080025import android.Manifest;
Wyatt Rileycf879db2017-01-12 13:57:38 -080026import android.annotation.NonNull;
Wyatt Riley49097c02018-03-15 09:14:43 -070027import android.annotation.Nullable;
Maggieaa080f92018-01-04 15:35:11 -080028import android.app.ActivityManager;
29import android.app.AppOpsManager;
30import android.app.PendingIntent;
31import android.content.BroadcastReceiver;
32import android.content.ContentResolver;
33import android.content.Context;
34import android.content.Intent;
35import android.content.IntentFilter;
36import android.content.pm.ApplicationInfo;
37import android.content.pm.PackageInfo;
38import android.content.pm.PackageManager;
39import android.content.pm.PackageManager.NameNotFoundException;
40import android.content.pm.PackageManagerInternal;
41import android.content.pm.ResolveInfo;
42import android.content.pm.Signature;
43import android.content.res.Resources;
44import android.database.ContentObserver;
45import android.hardware.location.ActivityRecognitionHardware;
46import android.location.Address;
47import android.location.Criteria;
48import android.location.GeocoderParams;
49import android.location.Geofence;
50import android.location.IBatchedLocationCallback;
51import android.location.IGnssMeasurementsListener;
52import android.location.IGnssNavigationMessageListener;
53import android.location.IGnssStatusListener;
Maggieaa080f92018-01-04 15:35:11 -080054import android.location.IGpsGeofenceHardware;
55import android.location.ILocationListener;
56import android.location.ILocationManager;
57import android.location.INetInitiatedListener;
58import android.location.Location;
59import android.location.LocationManager;
Maggieaa080f92018-01-04 15:35:11 -080060import android.location.LocationRequest;
61import android.os.Binder;
62import android.os.Bundle;
63import android.os.Handler;
64import android.os.IBinder;
65import android.os.Looper;
66import android.os.Message;
67import android.os.PowerManager;
68import android.os.Process;
69import android.os.RemoteException;
70import android.os.SystemClock;
71import android.os.UserHandle;
72import android.os.UserManager;
73import android.os.WorkSource;
Narayan Kamath32684dd2018-01-08 17:32:51 +000074import android.os.WorkSource.WorkChain;
Maggieaa080f92018-01-04 15:35:11 -080075import android.provider.Settings;
76import android.text.TextUtils;
Soonil Nagarkar681d7112017-02-23 17:14:16 -080077import android.util.ArrayMap;
Soonil Nagarkar2b565df2017-02-14 13:33:23 -080078import android.util.ArraySet;
Maggieaa080f92018-01-04 15:35:11 -080079import android.util.EventLog;
80import android.util.Log;
81import android.util.Slog;
Yu-Han Yanga4d250e2018-10-02 21:29:20 -070082
destradaaea8a8a62014-06-23 18:19:03 -070083import com.android.internal.content.PackageMonitor;
84import com.android.internal.location.ProviderProperties;
85import com.android.internal.location.ProviderRequest;
86import com.android.internal.os.BackgroundThread;
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -070087import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060088import com.android.internal.util.DumpUtils;
Soonil Nagarkar1575a042018-10-24 17:54:54 -070089import com.android.server.location.AbstractLocationProvider;
destradaaa4fa3b52014-07-09 10:46:39 -070090import com.android.server.location.ActivityRecognitionProxy;
destradaaea8a8a62014-06-23 18:19:03 -070091import com.android.server.location.GeocoderProxy;
92import com.android.server.location.GeofenceManager;
93import com.android.server.location.GeofenceProxy;
Yu-Han Yang3557cc72018-03-21 12:48:36 -070094import com.android.server.location.GnssBatchingProvider;
Lifu Tang818aa2c2016-02-01 01:52:00 -080095import com.android.server.location.GnssLocationProvider;
96import com.android.server.location.GnssMeasurementsProvider;
97import com.android.server.location.GnssNavigationMessageProvider;
Anil Admal75b9fd62018-11-28 11:22:50 -080098import com.android.server.location.GnssStatusListenerHelper;
destradaaea8a8a62014-06-23 18:19:03 -070099import com.android.server.location.LocationBlacklist;
100import com.android.server.location.LocationFudger;
destradaaea8a8a62014-06-23 18:19:03 -0700101import com.android.server.location.LocationProviderProxy;
102import com.android.server.location.LocationRequestStatistics;
103import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
104import com.android.server.location.LocationRequestStatistics.PackageStatistics;
105import com.android.server.location.MockProvider;
106import com.android.server.location.PassiveProvider;
Yu-Han Yanga4d250e2018-10-02 21:29:20 -0700107
Mike Lockwood43e33f22010-03-26 10:41:48 -0400108import java.io.FileDescriptor;
109import java.io.PrintWriter;
110import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700111import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400112import java.util.HashMap;
113import java.util.HashSet;
114import java.util.List;
115import java.util.Map;
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800116import java.util.Map.Entry;
Wyatt Rileycf879db2017-01-12 13:57:38 -0800117import java.util.NoSuchElementException;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400118import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119
120/**
121 * The service class that manages LocationProviders and issues location
122 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 */
Victoria Lease5cd731a2012-12-19 15:04:21 -0800124public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -0800126 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700127
Olivier Gaillard7a222662017-11-20 16:07:24 +0000128 private static final String WAKELOCK_KEY = "*location*";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129
Victoria Lease37425c32012-10-16 16:08:48 -0700130 // Location resolution level: no location data whatsoever
131 private static final int RESOLUTION_LEVEL_NONE = 0;
132 // Location resolution level: coarse location data only
133 private static final int RESOLUTION_LEVEL_COARSE = 1;
134 // Location resolution level: fine location data
135 private static final int RESOLUTION_LEVEL_FINE = 2;
136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700138 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400139 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700140 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
141
142 private static final String NETWORK_LOCATION_SERVICE_ACTION =
Stan Chesnutt39062dd2013-07-22 14:33:30 -0700143 "com.android.location.service.v3.NetworkLocationProvider";
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700144 private static final String FUSED_LOCATION_SERVICE_ACTION =
145 "com.android.location.service.FusedLocationProvider";
146
147 private static final int MSG_LOCATION_CHANGED = 1;
148
David Christie1b9b7b12013-04-15 15:31:11 -0700149 private static final long NANOS_PER_MILLI = 1000000L;
150
David Christie0b837452013-07-29 16:02:13 -0700151 // The maximum interval a location request can have and still be considered "high power".
152 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
153
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700154 private static final int FOREGROUND_IMPORTANCE_CUTOFF
gomo48f1a642017-11-10 20:35:46 -0800155 = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700156
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800157 // default background throttling interval if not overriden in settings
Soonil Nagarkarde6780a2017-02-07 10:39:41 -0800158 private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800159
Wei Wangdd070f22018-06-21 11:29:40 -0700160 // Default value for maximum age of last location returned to applications with foreground-only
161 // location permissions.
162 private static final long DEFAULT_LAST_LOCATION_MAX_AGE_MS = 20 * 60 * 1000;
163
Nick Pellyf1be6862012-05-15 10:53:42 -0700164 // Location Providers may sometimes deliver location updates
165 // slightly faster that requested - provide grace period so
166 // we don't unnecessarily filter events that are otherwise on
167 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700168 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700169
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700170 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
171
172 private final Context mContext;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800173 private final AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700174
175 // used internally for synchronization
176 private final Object mLock = new Object();
177
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700178 // --- fields below are final after systemRunning() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700179 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700180 private GeofenceManager mGeofenceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700181 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700182 private PowerManager mPowerManager;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800183 private ActivityManager mActivityManager;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700184 private UserManager mUserManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700185 private GeocoderProxy mGeocodeProvider;
Anil Admal75b9fd62018-11-28 11:22:50 -0800186 private GnssStatusListenerHelper mGnssStatusProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700187 private INetInitiatedListener mNetInitiatedListener;
188 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700189 private PassiveProvider mPassiveProvider; // track passive provider for special cases
190 private LocationBlacklist mBlacklist;
Lifu Tang818aa2c2016-02-01 01:52:00 -0800191 private GnssMeasurementsProvider mGnssMeasurementsProvider;
192 private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
Wei Wang980b7c22018-12-06 17:53:00 -0800193 private String mLocationControllerExtraPackage;
194 private boolean mLocationControllerExtraPackageEnabled;
Wei Liu5241a4c2015-05-11 14:00:36 -0700195 private IGpsGeofenceHardware mGpsGeofenceProxy;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700196
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700197 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700199 // Mock (test) providers
200 private final HashMap<String, MockProvider> mMockProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800201 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700203 // all receivers
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800204 private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700206 // currently installed providers (with mocks replacing real providers)
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700207 private final ArrayList<LocationProvider> mProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800208 new ArrayList<>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400209
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700210 // real providers, saved here when mocked out
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700211 private final HashMap<String, LocationProvider> mRealProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800212 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700214 // mapping from provider name to provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700215 private final HashMap<String, LocationProvider> mProvidersByName =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800216 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700218 // mapping from provider name to all its UpdateRecords
219 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800220 new HashMap<>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700221
David Christie2ff96af2014-01-30 16:09:37 -0800222 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
223
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700224 // mapping from provider name to last known location
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800225 private final HashMap<String, Location> mLastLocation = new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226
David Christie1b9b7b12013-04-15 15:31:11 -0700227 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
228 // locations stored here are not fudged for coarse permissions.
229 private final HashMap<String, Location> mLastLocationCoarseInterval =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800230 new HashMap<>();
David Christie1b9b7b12013-04-15 15:31:11 -0700231
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800232 // all providers that operate over proxy, for authorizing incoming location and whitelisting
233 // throttling
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700234 private final ArrayList<LocationProviderProxy> mProxyProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800235 new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236
Soonil Nagarkar2b565df2017-02-14 13:33:23 -0800237 private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800238
Wyatt Riley11cc7492018-01-17 08:48:27 -0800239 private final ArrayMap<IBinder, Identity> mGnssMeasurementsListeners = new ArrayMap<>();
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800240
Wyatt Riley11cc7492018-01-17 08:48:27 -0800241 private final ArrayMap<IBinder, Identity>
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800242 mGnssNavigationMessageListeners = new ArrayMap<>();
243
Victoria Lease38389b62012-09-30 11:44:22 -0700244 // current active user on the device - other users are denied location data
Xiaohui Chena4490622015-09-22 15:29:31 -0700245 private int mCurrentUserId = UserHandle.USER_SYSTEM;
gomo48f1a642017-11-10 20:35:46 -0800246 private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
Victoria Lease38389b62012-09-30 11:44:22 -0700247
Wei Wangdd070f22018-06-21 11:29:40 -0700248 // Maximum age of last location returned to clients with foreground-only location permissions.
249 private long mLastLocationMaxAgeMs;
250
Lifu Tang9363b942016-02-16 18:07:00 -0800251 private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
Lifu Tang82f893d2016-01-21 18:15:33 -0800252
Siddharth Raybb608c82017-03-16 11:33:34 -0700253 private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
Wyatt Rileyaa420d52017-07-03 15:14:42 -0700254
Yu-Han Yang3557cc72018-03-21 12:48:36 -0700255 private GnssBatchingProvider mGnssBatchingProvider;
Wyatt Rileycf879db2017-01-12 13:57:38 -0800256 private IBatchedLocationCallback mGnssBatchingCallback;
257 private LinkedCallback mGnssBatchingDeathCallback;
258 private boolean mGnssBatchingInProgress = false;
259
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700260 public LocationManagerService(Context context) {
261 super();
262 mContext = context;
gomo48f1a642017-11-10 20:35:46 -0800263 mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800264
Svet Ganovadc1cf42015-06-15 16:36:24 -0700265 // Let the package manager query which are the default location
266 // providers as they get certain permissions granted by default.
267 PackageManagerInternal packageManagerInternal = LocalServices.getService(
268 PackageManagerInternal.class);
269 packageManagerInternal.setLocationPackagesProvider(
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700270 userId -> mContext.getResources().getStringArray(
271 com.android.internal.R.array.config_locationProviderPackageNames));
Svet Ganovadc1cf42015-06-15 16:36:24 -0700272
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700273 if (D) Log.d(TAG, "Constructed");
274
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700275 // most startup is deferred until systemRunning()
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700276 }
277
Svetoslav Ganova0027152013-06-25 14:59:53 -0700278 public void systemRunning() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700279 synchronized (mLock) {
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700280 if (D) Log.d(TAG, "systemRunning()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700281
Victoria Lease5cd731a2012-12-19 15:04:21 -0800282 // fetch package manager
283 mPackageManager = mContext.getPackageManager();
284
Victoria Lease0aa28602013-05-29 15:28:26 -0700285 // fetch power manager
286 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800287
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800288 // fetch activity manager
289 mActivityManager
290 = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
291
Victoria Lease5cd731a2012-12-19 15:04:21 -0800292 // prepare worker thread
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700293 mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
Victoria Lease5cd731a2012-12-19 15:04:21 -0800294
295 // prepare mLocationHandler's dependents
296 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
297 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
298 mBlacklist.init();
299 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
300
Dianne Hackbornc2293022013-02-06 23:14:49 -0800301 // Monitor for app ops mode changes.
Dianne Hackborn9bb0ee92013-09-22 12:31:38 -0700302 AppOpsManager.OnOpChangedListener callback
303 = new AppOpsManager.OnOpChangedInternalListener() {
304 public void onOpChanged(int op, String packageName) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800305 synchronized (mLock) {
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700306 for (Receiver receiver : mReceivers.values()) {
307 receiver.updateMonitoring(true);
308 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800309 applyAllProviderRequirementsLocked();
310 }
311 }
312 };
Wei Wangdd070f22018-06-21 11:29:40 -0700313 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null,
314 AppOpsManager.WATCH_FOREGROUND_CHANGES, callback);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800315
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700316 PackageManager.OnPermissionsChangedListener permissionListener = uid -> {
317 synchronized (mLock) {
318 applyAllProviderRequirementsLocked();
David Christieb870dbf2015-06-22 12:42:53 -0700319 }
320 };
321 mPackageManager.addOnPermissionsChangeListener(permissionListener);
322
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800323 // listen for background/foreground changes
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700324 ActivityManager.OnUidImportanceListener uidImportanceListener =
325 (uid, importance) -> mLocationHandler.post(
326 () -> onUidImportanceChanged(uid, importance));
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800327 mActivityManager.addOnUidImportanceListener(uidImportanceListener,
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700328 FOREGROUND_IMPORTANCE_CUTOFF);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800329
Amith Yamasanib27528d2014-06-05 15:02:10 -0700330 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
331 updateUserProfiles(mCurrentUserId);
332
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800333 updateBackgroundThrottlingWhitelistLocked();
Wei Wangdd070f22018-06-21 11:29:40 -0700334 updateLastLocationMaxAgeLocked();
Soonil Nagarkar2b565df2017-02-14 13:33:23 -0800335
Victoria Lease5cd731a2012-12-19 15:04:21 -0800336 // prepare providers
337 loadProvidersLocked();
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700338 updateProvidersSettingsLocked();
339 for (LocationProvider provider : mProviders) {
340 applyRequirementsLocked(provider.getName());
341 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800342 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700343
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700344 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700345 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700346 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700347 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800348 @Override
349 public void onChange(boolean selfChange) {
350 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700351 updateProvidersSettingsLocked();
Victoria Lease5cd731a2012-12-19 15:04:21 -0800352 }
353 }
354 }, UserHandle.USER_ALL);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800355 mContext.getContentResolver().registerContentObserver(
356 Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS),
357 true,
358 new ContentObserver(mLocationHandler) {
359 @Override
360 public void onChange(boolean selfChange) {
361 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700362 for (LocationProvider provider : mProviders) {
363 applyRequirementsLocked(provider.getName());
364 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800365 }
366 }
367 }, UserHandle.USER_ALL);
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800368 mContext.getContentResolver().registerContentObserver(
Wei Wangdd070f22018-06-21 11:29:40 -0700369 Settings.Global.getUriFor(Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS),
370 true,
371 new ContentObserver(mLocationHandler) {
372 @Override
373 public void onChange(boolean selfChange) {
374 synchronized (mLock) {
375 updateLastLocationMaxAgeLocked();
376 }
377 }
378 }
379 );
380 mContext.getContentResolver().registerContentObserver(
gomo48f1a642017-11-10 20:35:46 -0800381 Settings.Global.getUriFor(
382 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
383 true,
384 new ContentObserver(mLocationHandler) {
385 @Override
386 public void onChange(boolean selfChange) {
387 synchronized (mLock) {
388 updateBackgroundThrottlingWhitelistLocked();
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700389 for (LocationProvider provider : mProviders) {
390 applyRequirementsLocked(provider.getName());
391 }
gomo48f1a642017-11-10 20:35:46 -0800392 }
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800393 }
gomo48f1a642017-11-10 20:35:46 -0800394 }, UserHandle.USER_ALL);
Wei Wangdd070f22018-06-21 11:29:40 -0700395
Victoria Lease5cd731a2012-12-19 15:04:21 -0800396 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700397
Victoria Lease38389b62012-09-30 11:44:22 -0700398 // listen for user change
399 IntentFilter intentFilter = new IntentFilter();
400 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700401 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
402 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
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);
Victoria Lease38389b62012-09-30 11:44:22 -0700413 }
414 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800415 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700416 }
417
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700418 private void onUidImportanceChanged(int uid, int importance) {
419 boolean foreground = isImportanceForeground(importance);
420 HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
421 synchronized (mLock) {
422 for (Entry<String, ArrayList<UpdateRecord>> entry
gomo48f1a642017-11-10 20:35:46 -0800423 : mRecordsByProvider.entrySet()) {
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700424 String provider = entry.getKey();
425 for (UpdateRecord record : entry.getValue()) {
426 if (record.mReceiver.mIdentity.mUid == uid
gomo48f1a642017-11-10 20:35:46 -0800427 && record.mIsForegroundUid != foreground) {
428 if (D) {
429 Log.d(TAG, "request from uid " + uid + " is now "
430 + (foreground ? "foreground" : "background)"));
431 }
Wyatt Rileyf7075e02018-04-12 17:54:26 -0700432 record.updateForeground(foreground);
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700433
434 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
435 affectedProviders.add(provider);
436 }
437 }
438 }
439 }
440 for (String provider : affectedProviders) {
441 applyRequirementsLocked(provider);
442 }
443
Wyatt Riley11cc7492018-01-17 08:48:27 -0800444 for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
Anil Admal75b9fd62018-11-28 11:22:50 -0800445 Identity callerIdentity = entry.getValue();
446 if (callerIdentity.mUid == uid) {
gomo48f1a642017-11-10 20:35:46 -0800447 if (D) {
448 Log.d(TAG, "gnss measurements listener from uid " + uid
449 + " is now " + (foreground ? "foreground" : "background)"));
450 }
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700451 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800452 mGnssMeasurementsProvider.addListener(
Anil Admal75b9fd62018-11-28 11:22:50 -0800453 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
454 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700455 } else {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800456 mGnssMeasurementsProvider.removeListener(
457 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700458 }
459 }
460 }
461
Wyatt Riley11cc7492018-01-17 08:48:27 -0800462 for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
Anil Admal75b9fd62018-11-28 11:22:50 -0800463 Identity callerIdentity = entry.getValue();
464 if (callerIdentity.mUid == uid) {
gomo48f1a642017-11-10 20:35:46 -0800465 if (D) {
466 Log.d(TAG, "gnss navigation message listener from uid "
467 + uid + " is now "
468 + (foreground ? "foreground" : "background)"));
469 }
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700470 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800471 mGnssNavigationMessageProvider.addListener(
Anil Admal75b9fd62018-11-28 11:22:50 -0800472 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
473 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700474 } else {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800475 mGnssNavigationMessageProvider.removeListener(
476 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700477 }
478 }
479 }
Anil Admal75b9fd62018-11-28 11:22:50 -0800480
481 // TODO(b/120449926): The GNSS status listeners should be handled similar to the above.
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700482 }
483 }
484
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800485 private static boolean isImportanceForeground(int importance) {
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700486 return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800487 }
488
Amith Yamasanib27528d2014-06-05 15:02:10 -0700489 /**
490 * Makes a list of userids that are related to the current user. This is
491 * relevant when using managed profiles. Otherwise the list only contains
492 * the current user.
493 *
494 * @param currentUserId the current user, who might have an alter-ego.
495 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700496 private void updateUserProfiles(int currentUserId) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700497 int[] profileIds = mUserManager.getProfileIdsWithDisabled(currentUserId);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700498 synchronized (mLock) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700499 mCurrentUserProfiles = profileIds;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700500 }
501 }
502
503 /**
504 * Checks if the specified userId matches any of the current foreground
505 * users stored in mCurrentUserProfiles.
506 */
507 private boolean isCurrentProfile(int userId) {
508 synchronized (mLock) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700509 return ArrayUtils.contains(mCurrentUserProfiles, userId);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700510 }
511 }
512
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700513 private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) {
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500514 PackageManager pm = mContext.getPackageManager();
515 String systemPackageName = mContext.getPackageName();
516 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
517
518 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
519 new Intent(FUSED_LOCATION_SERVICE_ACTION),
520 PackageManager.GET_META_DATA, mCurrentUserId);
521 for (ResolveInfo rInfo : rInfos) {
522 String packageName = rInfo.serviceInfo.packageName;
523
524 // Check that the signature is in the list of supported sigs. If it's not in
525 // this list the standard provider binding logic won't bind to it.
526 try {
527 PackageInfo pInfo;
528 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
529 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
530 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
531 ", but has wrong signature, ignoring");
532 continue;
533 }
534 } catch (NameNotFoundException e) {
535 Log.e(TAG, "missing package: " + packageName);
536 continue;
537 }
538
539 // Get the version info
540 if (rInfo.serviceInfo.metaData == null) {
541 Log.w(TAG, "Found fused provider without metadata: " + packageName);
542 continue;
543 }
544
545 int version = rInfo.serviceInfo.metaData.getInt(
546 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
547 if (version == 0) {
548 // This should be the fallback fused location provider.
549
550 // Make sure it's in the system partition.
551 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
552 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
553 continue;
554 }
555
556 // Check that the fallback is signed the same as the OS
557 // as a proxy for coreApp="true"
558 if (pm.checkSignatures(systemPackageName, packageName)
559 != PackageManager.SIGNATURE_MATCH) {
gomo48f1a642017-11-10 20:35:46 -0800560 if (D) {
561 Log.d(TAG, "Fallback candidate not signed the same as system: "
562 + packageName);
563 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500564 continue;
565 }
566
567 // Found a valid fallback.
568 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
569 return;
570 } else {
571 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
572 }
573 }
574
575 throw new IllegalStateException("Unable to find a fused location provider that is in the "
576 + "system partition with version 0 and signed with the platform certificate. "
577 + "Such a package is needed to provide a default fused location provider in the "
578 + "event that no other fused location provider has been installed or is currently "
579 + "available. For example, coreOnly boot mode when decrypting the data "
580 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
581 }
582
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700583 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700584 // create a passive location provider, which is always enabled
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700585 LocationProvider passiveProviderManager = new LocationProvider(
586 LocationManager.PASSIVE_PROVIDER);
587 PassiveProvider passiveProvider = new PassiveProvider(passiveProviderManager);
588
589 addProviderLocked(passiveProviderManager);
Victoria Lease5c24fd02012-10-01 11:00:50 -0700590 mPassiveProvider = passiveProvider;
591
Lifu Tang30f95a72016-01-07 23:20:38 -0800592 if (GnssLocationProvider.isSupported()) {
Wei Liu5241a4c2015-05-11 14:00:36 -0700593 // Create a gps location provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700594 LocationProvider gnssProviderManager = new LocationProvider(
595 LocationManager.GPS_PROVIDER);
596 GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext,
597 gnssProviderManager,
Wei Liu5241a4c2015-05-11 14:00:36 -0700598 mLocationHandler.getLooper());
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700599
Lifu Tang9363b942016-02-16 18:07:00 -0800600 mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
Wyatt Rileycf879db2017-01-12 13:57:38 -0800601 mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
Siddharth Raybb608c82017-03-16 11:33:34 -0700602 mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800603 mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
604 mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700605 addProviderLocked(gnssProviderManager);
606 mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProviderManager);
Lifu Tang818aa2c2016-02-01 01:52:00 -0800607 mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
608 mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800609 mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700610 }
611
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700612 /*
613 Load package name(s) containing location provider support.
614 These packages can contain services implementing location providers:
615 Geocoder Provider, Network Location Provider, and
616 Fused Location Provider. They will each be searched for
617 service components implementing these providers.
618 The location framework also has support for installation
619 of new location providers at run-time. The new package does not
620 have to be explicitly listed here, however it must have a signature
621 that matches the signature of at least one package on this list.
622 */
623 Resources resources = mContext.getResources();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500624 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700625 com.android.internal.R.array.config_locationProviderPackageNames);
gomo48f1a642017-11-10 20:35:46 -0800626 if (D) {
627 Log.d(TAG, "certificates for location providers pulled from: " +
628 Arrays.toString(pkgs));
629 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500630
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700631 ensureFallbackFusedProviderPresentLocked(pkgs);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700632
633 // bind to network provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700634
635 LocationProvider networkProviderManager = new LocationProvider(
636 LocationManager.NETWORK_PROVIDER);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700637 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
638 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700639 networkProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700640 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700641 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
642 com.android.internal.R.string.config_networkLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700643 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700644 if (networkProvider != null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700645 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProviderManager);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700646 mProxyProviders.add(networkProvider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700647 addProviderLocked(networkProviderManager);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700648 } else {
gomo48f1a642017-11-10 20:35:46 -0800649 Slog.w(TAG, "no network location provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700650 }
651
652 // bind to fused provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700653 LocationProvider fusedProviderManager = new LocationProvider(
654 LocationManager.FUSED_PROVIDER);
655 LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700656 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700657 fusedProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700658 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700659 com.android.internal.R.bool.config_enableFusedLocationOverlay,
660 com.android.internal.R.string.config_fusedLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700661 com.android.internal.R.array.config_locationProviderPackageNames);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700662 if (fusedProvider != null) {
663 addProviderLocked(fusedProviderManager);
664 mProxyProviders.add(fusedProvider);
665 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedProviderManager);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700666 } else {
667 Slog.e(TAG, "no fused location provider found",
668 new IllegalStateException("Location service needs a fused location provider"));
669 }
670
671 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700672 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
673 com.android.internal.R.bool.config_enableGeocoderOverlay,
674 com.android.internal.R.string.config_geocoderProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700675 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700676 if (mGeocodeProvider == null) {
gomo48f1a642017-11-10 20:35:46 -0800677 Slog.e(TAG, "no geocoder provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700678 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700679
destradaaf9a274c2014-07-25 15:11:56 -0700680 // bind to geofence provider
681 GeofenceProxy provider = GeofenceProxy.createAndBind(
gomo48f1a642017-11-10 20:35:46 -0800682 mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
destradaaf9a274c2014-07-25 15:11:56 -0700683 com.android.internal.R.string.config_geofenceProviderPackageName,
684 com.android.internal.R.array.config_locationProviderPackageNames,
Wei Liu5241a4c2015-05-11 14:00:36 -0700685 mGpsGeofenceProxy,
Jiyong Park4cc3a1c2018-03-08 16:43:07 +0900686 null);
destradaaf9a274c2014-07-25 15:11:56 -0700687 if (provider == null) {
gomo48f1a642017-11-10 20:35:46 -0800688 Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
destradaa0682809a2013-08-12 18:50:30 -0700689 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900690
destradaa6e2fe752015-06-23 17:25:53 -0700691 // bind to hardware activity recognition
692 boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported();
693 ActivityRecognitionHardware activityRecognitionHardware = null;
694 if (activityRecognitionHardwareIsSupported) {
695 activityRecognitionHardware = ActivityRecognitionHardware.getInstance(mContext);
destradaaa4fa3b52014-07-09 10:46:39 -0700696 } else {
destradaa6b4893a2016-05-03 15:33:43 -0700697 Slog.d(TAG, "Hardware Activity-Recognition not supported.");
destradaaa4fa3b52014-07-09 10:46:39 -0700698 }
destradaa6e2fe752015-06-23 17:25:53 -0700699 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
700 mContext,
destradaa6e2fe752015-06-23 17:25:53 -0700701 activityRecognitionHardwareIsSupported,
702 activityRecognitionHardware,
703 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
704 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
705 com.android.internal.R.array.config_locationProviderPackageNames);
706 if (proxy == null) {
destradaa6b4893a2016-05-03 15:33:43 -0700707 Slog.d(TAG, "Unable to bind ActivityRecognitionProxy.");
destradaa6e2fe752015-06-23 17:25:53 -0700708 }
destradaaa4fa3b52014-07-09 10:46:39 -0700709
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900710 String[] testProviderStrings = resources.getStringArray(
711 com.android.internal.R.array.config_testLocationProviders);
712 for (String testProviderString : testProviderStrings) {
713 String fragments[] = testProviderString.split(",");
714 String name = fragments[0].trim();
715 if (mProvidersByName.get(name) != null) {
716 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
717 }
718 ProviderProperties properties = new ProviderProperties(
719 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
720 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
721 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
722 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
723 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
724 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
725 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
726 Integer.parseInt(fragments[8]) /* powerRequirement */,
727 Integer.parseInt(fragments[9]) /* accuracy */);
728 addTestProviderLocked(name, properties);
729 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700730 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700731
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700733 * Called when the device's active user changes.
gomo48f1a642017-11-10 20:35:46 -0800734 *
Victoria Lease38389b62012-09-30 11:44:22 -0700735 * @param userId the new active user's UserId
736 */
737 private void switchUser(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800738 if (mCurrentUserId == userId) {
739 return;
740 }
Victoria Lease83762d22012-10-03 13:51:17 -0700741 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800742 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700743 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700744 mLastLocation.clear();
David Christie1b9b7b12013-04-15 15:31:11 -0700745 mLastLocationCoarseInterval.clear();
Amith Yamasanib27528d2014-06-05 15:02:10 -0700746 updateUserProfiles(userId);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700747 updateProvidersSettingsLocked();
748 mCurrentUserId = userId;
Victoria Lease38389b62012-09-30 11:44:22 -0700749 }
750 }
751
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800752 private static final class Identity {
753 final int mUid;
754 final int mPid;
755 final String mPackageName;
756
757 Identity(int uid, int pid, String packageName) {
758 mUid = uid;
759 mPid = pid;
760 mPackageName = packageName;
761 }
762 }
763
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700764 private class LocationProvider implements AbstractLocationProvider.LocationProviderManager {
765
766 private final String mName;
767 private AbstractLocationProvider mProvider;
768
769 // whether the provider is enabled in location settings
770 private boolean mSettingsEnabled;
771
772 // whether the provider considers itself enabled
773 private volatile boolean mEnabled;
774
775 @Nullable
776 private volatile ProviderProperties mProperties;
777
778 private LocationProvider(String name) {
779 mName = name;
780 // TODO: initialize settings enabled?
781 }
782
783 @Override
784 public void onAttachProvider(AbstractLocationProvider provider, boolean initiallyEnabled) {
785 checkState(mProvider == null);
786
787 // the provider is not yet fully constructed at this point, so we may not do anything
788 // except save a reference for later use here. do not call any provider methods.
789 mProvider = provider;
790 mEnabled = initiallyEnabled;
791 mProperties = null;
792 }
793
794 public String getName() {
795 return mName;
796 }
797
798 public boolean isEnabled() {
799 return mSettingsEnabled && mEnabled;
800 }
801
802 @Nullable
803 public ProviderProperties getProperties() {
804 return mProperties;
805 }
806
807 public void setRequest(ProviderRequest request, WorkSource workSource) {
808 mProvider.setRequest(request, workSource);
809 }
810
811 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
812 pw.println(mName + " provider:");
813 pw.println(" setting=" + mSettingsEnabled);
814 pw.println(" enabled=" + mEnabled);
815 pw.println(" properties=" + mProperties);
816 mProvider.dump(fd, pw, args);
817 }
818
819 public long getStatusUpdateTime() {
820 return mProvider.getStatusUpdateTime();
821 }
822
823 public int getStatus(Bundle extras) {
824 return mProvider.getStatus(extras);
825 }
826
827 public void sendExtraCommand(String command, Bundle extras) {
828 mProvider.sendExtraCommand(command, extras);
829 }
830
831 // called from any thread
832 @Override
833 public void onReportLocation(Location location) {
834 runOnHandler(() -> LocationManagerService.this.reportLocation(location,
835 mProvider == mPassiveProvider));
836 }
837
838 // called from any thread
839 @Override
840 public void onReportLocation(List<Location> locations) {
841 runOnHandler(() -> LocationManagerService.this.reportLocationBatch(locations));
842 }
843
844 // called from any thread
845 @Override
846 public void onSetEnabled(boolean enabled) {
847 runOnHandler(() -> {
848 if (enabled == mEnabled) {
849 return;
850 }
851
852 mEnabled = enabled;
853
854 if (!mSettingsEnabled) {
855 // this provider was disabled in settings anyways, so a change to it's own
856 // enabled status won't have any affect.
857 return;
858 }
859
860 // traditionally clients can listen for changes to the LOCATION_PROVIDERS_ALLOWED
861 // setting to detect when providers are enabled or disabled (even though they aren't
862 // supposed to). to continue to support this we must force a change to this setting.
863 // we use the fused provider because this is forced to be always enabled in settings
864 // anyways, and so won't have any visible effect beyond triggering content observers
865 Settings.Secure.putStringForUser(mContext.getContentResolver(),
866 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
867 "+" + LocationManager.FUSED_PROVIDER, mCurrentUserId);
868 Settings.Secure.putStringForUser(mContext.getContentResolver(),
869 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
870 "-" + LocationManager.FUSED_PROVIDER, mCurrentUserId);
871
872 synchronized (mLock) {
873 if (!enabled) {
874 // If any provider has been disabled, clear all last locations for all
875 // providers. This is to be on the safe side in case a provider has location
876 // derived from this disabled provider.
877 mLastLocation.clear();
878 mLastLocationCoarseInterval.clear();
879 }
880
881 updateProviderListenersLocked(mName);
882 }
883
884 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
885 UserHandle.ALL);
886 });
887 }
888
889 @Override
890 public void onSetProperties(ProviderProperties properties) {
891 runOnHandler(() -> mProperties = properties);
892 }
893
894 private void setSettingsEnabled(boolean enabled) {
895 synchronized (mLock) {
896 if (mSettingsEnabled == enabled) {
897 return;
898 }
899
900 mSettingsEnabled = enabled;
901 if (!mSettingsEnabled) {
902 // if any provider has been disabled, clear all last locations for all
903 // providers. this is to be on the safe side in case a provider has location
904 // derived from this disabled provider.
905 mLastLocation.clear();
906 mLastLocationCoarseInterval.clear();
907 updateProviderListenersLocked(mName);
908 } else if (mEnabled) {
909 updateProviderListenersLocked(mName);
910 }
911 }
912 }
913
914 private void runOnHandler(Runnable runnable) {
915 if (Looper.myLooper() == mLocationHandler.getLooper()) {
916 runnable.run();
917 } else {
918 mLocationHandler.post(runnable);
919 }
920 }
921 }
922
Victoria Lease38389b62012-09-30 11:44:22 -0700923 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
925 * location updates.
926 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700927 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Yu-Han Yang24189822018-07-11 15:24:11 -0700928 private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800929 final Identity mIdentity;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700930 private final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700931
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700932 private final ILocationListener mListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -0700934 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700935 private final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
936 private final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700937
gomo48f1a642017-11-10 20:35:46 -0800938 final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700939
David Christie0b837452013-07-29 16:02:13 -0700940 // True if app ops has started monitoring this receiver for locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700941 private boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -0700942 // True if app ops has started monitoring this receiver for high power (gps) locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700943 private boolean mOpHighPowerMonitoring;
944 private int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -0700945 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700947 private Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -0700948 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800950 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700951 if (listener != null) {
952 mKey = listener.asBinder();
953 } else {
954 mKey = intent;
955 }
Victoria Lease37425c32012-10-16 16:08:48 -0700956 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800957 mIdentity = new Identity(uid, pid, packageName);
Narayan Kamath32684dd2018-01-08 17:32:51 +0000958 if (workSource != null && workSource.isEmpty()) {
David Christie82edc9b2013-07-19 11:31:42 -0700959 workSource = null;
960 }
961 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -0700962 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -0700963
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700964 updateMonitoring(true);
965
Victoria Lease0aa28602013-05-29 15:28:26 -0700966 // construct/configure wakelock
967 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -0700968 if (workSource == null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800969 workSource = new WorkSource(mIdentity.mUid, mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -0700970 }
971 mWakeLock.setWorkSource(workSource);
Yu-Han Yang24189822018-07-11 15:24:11 -0700972
973 // For a non-reference counted wakelock, each acquire will reset the timeout, and we
974 // only need to release it once.
975 mWakeLock.setReferenceCounted(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 }
977
978 @Override
979 public boolean equals(Object otherObj) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800980 return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 }
982
983 @Override
984 public int hashCode() {
985 return mKey.hashCode();
986 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400987
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 @Override
989 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700990 StringBuilder s = new StringBuilder();
991 s.append("Reciever[");
992 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800993 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700994 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700996 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700998 for (String p : mUpdateRecords.keySet()) {
999 s.append(" ").append(mUpdateRecords.get(p).toString());
1000 }
Wei Wangdd070f22018-06-21 11:29:40 -07001001 s.append(" monitoring location: ").append(mOpMonitoring);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001002 s.append("]");
1003 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004 }
1005
David Christie15b31912013-08-13 15:54:32 -07001006 /**
1007 * Update AppOp monitoring for this receiver.
1008 *
1009 * @param allow If true receiver is currently active, if false it's been removed.
1010 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001011 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -07001012 if (mHideFromAppOps) {
1013 return;
1014 }
1015
David Christie15b31912013-08-13 15:54:32 -07001016 boolean requestingLocation = false;
1017 boolean requestingHighPowerLocation = false;
1018 if (allow) {
1019 // See if receiver has any enabled update records. Also note if any update records
1020 // are high power (has a high power provider with an interval under a threshold).
1021 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001022 if (isAllowedByUserSettingsLockedForUser(updateRecord.mProvider,
1023 mCurrentUserId)) {
David Christie15b31912013-08-13 15:54:32 -07001024 requestingLocation = true;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001025 LocationManagerService.LocationProvider locationProvider
David Christie2ff96af2014-01-30 16:09:37 -08001026 = mProvidersByName.get(updateRecord.mProvider);
David Christie15b31912013-08-13 15:54:32 -07001027 ProviderProperties properties = locationProvider != null
1028 ? locationProvider.getProperties() : null;
1029 if (properties != null
1030 && properties.mPowerRequirement == Criteria.POWER_HIGH
1031 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
1032 requestingHighPowerLocation = true;
1033 break;
1034 }
1035 }
1036 }
1037 }
1038
David Christie0b837452013-07-29 16:02:13 -07001039 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -07001040 mOpMonitoring = updateMonitoring(
1041 requestingLocation,
1042 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001043 AppOpsManager.OP_MONITOR_LOCATION);
1044
1045 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -07001046 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -07001047 mOpHighPowerMonitoring = updateMonitoring(
1048 requestingHighPowerLocation,
1049 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001050 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -07001051 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -07001052 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -07001053 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
1054 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1055 }
David Christie0b837452013-07-29 16:02:13 -07001056 }
1057
1058 /**
1059 * Update AppOps monitoring for a single location request and op type.
1060 *
gomo48f1a642017-11-10 20:35:46 -08001061 * @param allowMonitoring True if monitoring is allowed for this request/op.
David Christie0b837452013-07-29 16:02:13 -07001062 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
gomo48f1a642017-11-10 20:35:46 -08001063 * @param op AppOps code for the op to update.
David Christie0b837452013-07-29 16:02:13 -07001064 * @return True if monitoring is on for this request/op after updating.
1065 */
1066 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
1067 int op) {
1068 if (!currentlyMonitoring) {
1069 if (allowMonitoring) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001070 return mAppOps.startOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001071 == AppOpsManager.MODE_ALLOWED;
1072 }
1073 } else {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001074 if (!allowMonitoring
Wei Wangdd070f22018-06-21 11:29:40 -07001075 || mAppOps.noteOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001076 != AppOpsManager.MODE_ALLOWED) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001077 mAppOps.finishOp(op, mIdentity.mUid, mIdentity.mPackageName);
David Christie0b837452013-07-29 16:02:13 -07001078 return false;
1079 }
1080 }
1081
1082 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001083 }
1084
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001085 public boolean isListener() {
1086 return mListener != null;
1087 }
1088
1089 public boolean isPendingIntent() {
1090 return mPendingIntent != null;
1091 }
1092
1093 public ILocationListener getListener() {
1094 if (mListener != null) {
1095 return mListener;
1096 }
1097 throw new IllegalStateException("Request for non-existent listener");
1098 }
1099
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001100 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
1101 if (mListener != null) {
1102 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001103 synchronized (this) {
1104 // synchronize to ensure incrementPendingBroadcastsLocked()
1105 // is called before decrementPendingBroadcasts()
1106 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -07001107 // call this after broadcasting so we do not increment
1108 // if we throw an exeption.
1109 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001110 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001111 } catch (RemoteException e) {
1112 return false;
1113 }
1114 } else {
1115 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -08001116 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
1118 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001119 synchronized (this) {
1120 // synchronize to ensure incrementPendingBroadcastsLocked()
1121 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001122 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001123 getResolutionPermission(mAllowedResolutionLevel),
1124 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001125 // call this after broadcasting so we do not increment
1126 // if we throw an exeption.
1127 incrementPendingBroadcastsLocked();
1128 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129 } catch (PendingIntent.CanceledException e) {
1130 return false;
1131 }
1132 }
1133 return true;
1134 }
1135
1136 public boolean callLocationChangedLocked(Location location) {
1137 if (mListener != null) {
1138 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001139 synchronized (this) {
1140 // synchronize to ensure incrementPendingBroadcastsLocked()
1141 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001142 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -07001143 // call this after broadcasting so we do not increment
1144 // if we throw an exeption.
1145 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001146 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001147 } catch (RemoteException e) {
1148 return false;
1149 }
1150 } else {
1151 Intent locationChanged = new Intent();
gomo48f1a642017-11-10 20:35:46 -08001152 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED,
1153 new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001154 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001155 synchronized (this) {
1156 // synchronize to ensure incrementPendingBroadcastsLocked()
1157 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001158 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001159 getResolutionPermission(mAllowedResolutionLevel),
1160 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001161 // call this after broadcasting so we do not increment
1162 // if we throw an exeption.
1163 incrementPendingBroadcastsLocked();
1164 }
1165 } catch (PendingIntent.CanceledException e) {
1166 return false;
1167 }
1168 }
1169 return true;
1170 }
1171
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001172 private boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -07001173 // First update AppOp monitoring.
1174 // An app may get/lose location access as providers are enabled/disabled.
1175 updateMonitoring(true);
1176
Mike Lockwood48f17512009-04-23 09:12:08 -07001177 if (mListener != null) {
1178 try {
1179 synchronized (this) {
1180 // synchronize to ensure incrementPendingBroadcastsLocked()
1181 // is called before decrementPendingBroadcasts()
1182 if (enabled) {
1183 mListener.onProviderEnabled(provider);
1184 } else {
1185 mListener.onProviderDisabled(provider);
1186 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001187 // call this after broadcasting so we do not increment
1188 // if we throw an exeption.
1189 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001190 }
1191 } catch (RemoteException e) {
1192 return false;
1193 }
1194 } else {
1195 Intent providerIntent = new Intent();
1196 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
1197 try {
1198 synchronized (this) {
1199 // synchronize to ensure incrementPendingBroadcastsLocked()
1200 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001201 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001202 getResolutionPermission(mAllowedResolutionLevel),
1203 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001204 // call this after broadcasting so we do not increment
1205 // if we throw an exeption.
1206 incrementPendingBroadcastsLocked();
1207 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001208 } catch (PendingIntent.CanceledException e) {
1209 return false;
1210 }
1211 }
1212 return true;
1213 }
1214
Nick Pellyf1be6862012-05-15 10:53:42 -07001215 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001217 if (D) Log.d(TAG, "Location listener died");
1218
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001219 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001220 removeUpdatesLocked(this);
1221 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001222 synchronized (this) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001223 clearPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001224 }
1225 }
1226
Nick Pellye0fd6932012-07-11 10:26:13 -07001227 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001228 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1229 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001230 synchronized (this) {
1231 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001232 }
1233 }
1234
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001235 // this must be called while synchronized by caller in a synchronized block
1236 // containing the sending of the broadcaset
1237 private void incrementPendingBroadcastsLocked() {
Yu-Han Yang24189822018-07-11 15:24:11 -07001238 mPendingBroadcasts++;
1239 mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001240 }
1241
1242 private void decrementPendingBroadcastsLocked() {
1243 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001244 if (mWakeLock.isHeld()) {
1245 mWakeLock.release();
1246 }
1247 }
1248 }
1249
1250 public void clearPendingBroadcastsLocked() {
1251 if (mPendingBroadcasts > 0) {
1252 mPendingBroadcasts = 0;
1253 if (mWakeLock.isHeld()) {
1254 mWakeLock.release();
1255 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001256 }
1257 }
1258 }
1259
Nick Pellye0fd6932012-07-11 10:26:13 -07001260 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001261 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001262 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -04001263 //the receiver list if it is not found. If it is not found then the
1264 //LocationListener was removed when it had a pending broadcast and should
1265 //not be added back.
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001266 synchronized (mLock) {
1267 IBinder binder = listener.asBinder();
1268 Receiver receiver = mReceivers.get(binder);
1269 if (receiver != null) {
1270 synchronized (receiver) {
1271 // so wakelock calls will succeed
1272 long identity = Binder.clearCallingIdentity();
1273 receiver.decrementPendingBroadcastsLocked();
1274 Binder.restoreCallingIdentity(identity);
David Christie2ff96af2014-01-30 16:09:37 -08001275 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001276 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277 }
1278 }
1279
Lifu Tang82f893d2016-01-21 18:15:33 -08001280 /**
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001281 * Returns the year of the GNSS hardware.
Lifu Tang82f893d2016-01-21 18:15:33 -08001282 */
1283 @Override
Lifu Tang9363b942016-02-16 18:07:00 -08001284 public int getGnssYearOfHardware() {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001285 if (mGnssSystemInfoProvider != null) {
Lifu Tang9363b942016-02-16 18:07:00 -08001286 return mGnssSystemInfoProvider.getGnssYearOfHardware();
Lifu Tang82f893d2016-01-21 18:15:33 -08001287 } else {
1288 return 0;
1289 }
1290 }
1291
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001292
1293 /**
1294 * Returns the model name of the GNSS hardware.
1295 */
1296 @Override
Wyatt Riley49097c02018-03-15 09:14:43 -07001297 @Nullable
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001298 public String getGnssHardwareModelName() {
1299 if (mGnssSystemInfoProvider != null) {
1300 return mGnssSystemInfoProvider.getGnssHardwareModelName();
1301 } else {
Wyatt Riley49097c02018-03-15 09:14:43 -07001302 return null;
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001303 }
1304 }
1305
Wyatt Rileycf879db2017-01-12 13:57:38 -08001306 /**
1307 * Runs some checks for GNSS (FINE) level permissions, used by several methods which directly
1308 * (try to) access GNSS information at this layer.
1309 */
1310 private boolean hasGnssPermissions(String packageName) {
1311 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1312 checkResolutionLevelIsSufficientForProviderUse(
1313 allowedResolutionLevel,
1314 LocationManager.GPS_PROVIDER);
1315
1316 int pid = Binder.getCallingPid();
1317 int uid = Binder.getCallingUid();
1318 long identity = Binder.clearCallingIdentity();
1319 boolean hasLocationAccess;
1320 try {
1321 hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1322 } finally {
1323 Binder.restoreCallingIdentity(identity);
1324 }
1325
1326 return hasLocationAccess;
1327 }
1328
1329 /**
1330 * Returns the GNSS batching size, if available.
1331 */
1332 @Override
1333 public int getGnssBatchSize(String packageName) {
1334 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1335 "Location Hardware permission not granted to access hardware batching");
1336
1337 if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
Yu-Han Yang3557cc72018-03-21 12:48:36 -07001338 return mGnssBatchingProvider.getBatchSize();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001339 } else {
1340 return 0;
1341 }
1342 }
1343
1344 /**
1345 * Adds a callback for GNSS Batching events, if permissions allow, which are transported
1346 * to potentially multiple listeners by the BatchedLocationCallbackTransport above this.
1347 */
1348 @Override
1349 public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
1350 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1351 "Location Hardware permission not granted to access hardware batching");
1352
1353 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1354 return false;
1355 }
1356
1357 mGnssBatchingCallback = callback;
1358 mGnssBatchingDeathCallback = new LinkedCallback(callback);
1359 try {
1360 callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
1361 } catch (RemoteException e) {
1362 // if the remote process registering the listener is already dead, just swallow the
1363 // exception and return
1364 Log.e(TAG, "Remote listener already died.", e);
1365 return false;
1366 }
1367
1368 return true;
1369 }
1370
1371 private class LinkedCallback implements IBinder.DeathRecipient {
1372 private final IBatchedLocationCallback mCallback;
1373
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001374 private LinkedCallback(@NonNull IBatchedLocationCallback callback) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001375 mCallback = callback;
1376 }
1377
1378 @NonNull
1379 public IBatchedLocationCallback getUnderlyingListener() {
1380 return mCallback;
1381 }
1382
1383 @Override
1384 public void binderDied() {
1385 Log.d(TAG, "Remote Batching Callback died: " + mCallback);
1386 stopGnssBatch();
1387 removeGnssBatchingCallback();
1388 }
1389 }
1390
1391 /**
1392 * Removes callback for GNSS batching
1393 */
1394 @Override
1395 public void removeGnssBatchingCallback() {
1396 try {
1397 mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
1398 0 /* flags */);
1399 } catch (NoSuchElementException e) {
1400 // if the death callback isn't connected (it should be...), log error, swallow the
1401 // exception and return
1402 Log.e(TAG, "Couldn't unlink death callback.", e);
1403 }
1404 mGnssBatchingCallback = null;
1405 mGnssBatchingDeathCallback = null;
1406 }
1407
1408
1409 /**
1410 * Starts GNSS batching, if available.
1411 */
1412 @Override
1413 public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
1414 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1415 "Location Hardware permission not granted to access hardware batching");
1416
1417 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1418 return false;
1419 }
1420
1421 if (mGnssBatchingInProgress) {
1422 // Current design does not expect multiple starts to be called repeatedly
1423 Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
1424 // Try to clean up anyway, and continue
1425 stopGnssBatch();
1426 }
1427
1428 mGnssBatchingInProgress = true;
1429 return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
1430 }
1431
1432 /**
1433 * Flushes a GNSS batch in progress
1434 */
1435 @Override
1436 public void flushGnssBatch(String packageName) {
1437 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1438 "Location Hardware permission not granted to access hardware batching");
1439
1440 if (!hasGnssPermissions(packageName)) {
1441 Log.e(TAG, "flushGnssBatch called without GNSS permissions");
1442 return;
1443 }
1444
1445 if (!mGnssBatchingInProgress) {
1446 Log.w(TAG, "flushGnssBatch called with no batch in progress");
1447 }
1448
1449 if (mGnssBatchingProvider != null) {
gomo48f1a642017-11-10 20:35:46 -08001450 mGnssBatchingProvider.flush();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001451 }
1452 }
1453
1454 /**
1455 * Stops GNSS batching
1456 */
1457 @Override
1458 public boolean stopGnssBatch() {
1459 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1460 "Location Hardware permission not granted to access hardware batching");
1461
1462 if (mGnssBatchingProvider != null) {
1463 mGnssBatchingInProgress = false;
1464 return mGnssBatchingProvider.stop();
gomo48f1a642017-11-10 20:35:46 -08001465 } else {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001466 return false;
1467 }
1468 }
1469
1470 @Override
1471 public void reportLocationBatch(List<Location> locations) {
1472 checkCallerIsProvider();
1473
1474 // Currently used only for GNSS locations - update permissions check if changed
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001475 if (isAllowedByUserSettingsLockedForUser(LocationManager.GPS_PROVIDER, mCurrentUserId)) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001476 if (mGnssBatchingCallback == null) {
1477 Slog.e(TAG, "reportLocationBatch() called without active Callback");
1478 return;
1479 }
1480 try {
1481 mGnssBatchingCallback.onLocationBatch(locations);
1482 } catch (RemoteException e) {
1483 Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
1484 }
1485 } else {
1486 Slog.w(TAG, "reportLocationBatch() called without user permission, locations blocked");
1487 }
1488 }
1489
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001490 private void addProviderLocked(LocationProvider provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001491 mProviders.add(provider);
1492 mProvidersByName.put(provider.getName(), provider);
1493 }
1494
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001495 private void removeProviderLocked(LocationProvider provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001496 mProviders.remove(provider);
1497 mProvidersByName.remove(provider.getName());
1498 }
1499
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001500 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -08001501 * Returns "true" if access to the specified location provider is allowed by the specified
1502 * user's settings. Access to all location providers is forbidden to non-location-provider
1503 * processes belonging to background users.
1504 *
1505 * @param provider the name of the location provider
Maggie2a9409e2018-03-21 11:47:28 -07001506 * @param userId the user id to query
Victoria Lease09eeaec2013-02-05 11:34:13 -08001507 */
Maggie2a9409e2018-03-21 11:47:28 -07001508 private boolean isAllowedByUserSettingsLockedForUser(String provider, int userId) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001509 if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1510 return isLocationEnabledForUser(userId);
Maggie2a9409e2018-03-21 11:47:28 -07001511 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001512 if (LocationManager.FUSED_PROVIDER.equals(provider)) {
1513 return isLocationEnabledForUser(userId);
Maggie2a9409e2018-03-21 11:47:28 -07001514 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001515 synchronized (mLock) {
1516 if (mMockProviders.containsKey(provider)) {
1517 return isLocationEnabledForUser(userId);
1518 }
1519 }
1520
1521 long identity = Binder.clearCallingIdentity();
1522 try {
1523 // Use system settings
1524 ContentResolver cr = mContext.getContentResolver();
1525 String allowedProviders = Settings.Secure.getStringForUser(
1526 cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId);
1527 return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
1528 } finally {
1529 Binder.restoreCallingIdentity(identity);
1530 }
Maggie2a9409e2018-03-21 11:47:28 -07001531 }
1532
1533
1534 /**
1535 * Returns "true" if access to the specified location provider is allowed by the specified
1536 * user's settings. Access to all location providers is forbidden to non-location-provider
1537 * processes belonging to background users.
1538 *
1539 * @param provider the name of the location provider
1540 * @param uid the requestor's UID
1541 * @param userId the user id to query
1542 */
1543 private boolean isAllowedByUserSettingsLocked(String provider, int uid, int userId) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001544 if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001545 return false;
1546 }
Maggie2a9409e2018-03-21 11:47:28 -07001547 return isAllowedByUserSettingsLockedForUser(provider, userId);
Victoria Lease09eeaec2013-02-05 11:34:13 -08001548 }
1549
1550 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001551 * Returns the permission string associated with the specified resolution level.
1552 *
1553 * @param resolutionLevel the resolution level
1554 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001555 */
Victoria Lease37425c32012-10-16 16:08:48 -07001556 private String getResolutionPermission(int resolutionLevel) {
1557 switch (resolutionLevel) {
1558 case RESOLUTION_LEVEL_FINE:
1559 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1560 case RESOLUTION_LEVEL_COARSE:
1561 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1562 default:
1563 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001565 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001566
Victoria Leaseda479c52012-10-15 15:24:16 -07001567 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001568 * Returns the resolution level allowed to the given PID/UID pair.
1569 *
1570 * @param pid the PID
1571 * @param uid the UID
1572 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -07001573 */
Victoria Lease37425c32012-10-16 16:08:48 -07001574 private int getAllowedResolutionLevel(int pid, int uid) {
1575 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001576 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001577 return RESOLUTION_LEVEL_FINE;
1578 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001579 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001580 return RESOLUTION_LEVEL_COARSE;
1581 } else {
1582 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001583 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001584 }
1585
1586 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001587 * Returns the resolution level allowed to the caller
1588 *
1589 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -07001590 */
Victoria Lease37425c32012-10-16 16:08:48 -07001591 private int getCallerAllowedResolutionLevel() {
1592 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1593 }
1594
1595 /**
1596 * Throw SecurityException if specified resolution level is insufficient to use geofences.
1597 *
1598 * @param allowedResolutionLevel resolution level allowed to caller
1599 */
1600 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1601 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001602 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1603 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604 }
1605
Victoria Lease37425c32012-10-16 16:08:48 -07001606 /**
1607 * Return the minimum resolution level required to use the specified location provider.
1608 *
1609 * @param provider the name of the location provider
1610 * @return minimum resolution level required for provider
1611 */
1612 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001613 if (LocationManager.GPS_PROVIDER.equals(provider) ||
1614 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1615 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001616 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -07001617 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1618 LocationManager.FUSED_PROVIDER.equals(provider)) {
1619 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001620 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001621 } else {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001622 for (LocationProvider lp : mProviders) {
1623 if (!lp.getName().equals(provider)) {
1624 continue;
1625 }
1626
Laurent Tu941221c2012-10-04 14:21:52 -07001627 ProviderProperties properties = lp.getProperties();
1628 if (properties != null) {
1629 if (properties.mRequiresSatellite) {
1630 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001631 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001632 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1633 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001634 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001635 }
1636 }
1637 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001638 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001639
Victoria Lease37425c32012-10-16 16:08:48 -07001640 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001641 }
1642
Victoria Lease37425c32012-10-16 16:08:48 -07001643 /**
1644 * Throw SecurityException if specified resolution level is insufficient to use the named
1645 * location provider.
1646 *
1647 * @param allowedResolutionLevel resolution level allowed to caller
gomo48f1a642017-11-10 20:35:46 -08001648 * @param providerName the name of the location provider
Victoria Lease37425c32012-10-16 16:08:48 -07001649 */
1650 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1651 String providerName) {
1652 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1653 if (allowedResolutionLevel < requiredResolutionLevel) {
1654 switch (requiredResolutionLevel) {
1655 case RESOLUTION_LEVEL_FINE:
1656 throw new SecurityException("\"" + providerName + "\" location provider " +
1657 "requires ACCESS_FINE_LOCATION permission.");
1658 case RESOLUTION_LEVEL_COARSE:
1659 throw new SecurityException("\"" + providerName + "\" location provider " +
1660 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1661 default:
1662 throw new SecurityException("Insufficient permission for \"" + providerName +
1663 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001664 }
1665 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001666 }
1667
David Christie82edc9b2013-07-19 11:31:42 -07001668 /**
1669 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
1670 * for battery).
1671 */
David Christie40e57822013-07-30 11:36:48 -07001672 private void checkDeviceStatsAllowed() {
David Christie82edc9b2013-07-19 11:31:42 -07001673 mContext.enforceCallingOrSelfPermission(
1674 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
1675 }
1676
David Christie40e57822013-07-30 11:36:48 -07001677 private void checkUpdateAppOpsAllowed() {
1678 mContext.enforceCallingOrSelfPermission(
1679 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
1680 }
1681
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001682 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001683 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1684 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001685 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001686 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001687 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001688 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001689 }
1690 return -1;
1691 }
1692
Wei Wangb86334f2018-07-03 16:33:24 -07001693 private static String resolutionLevelToOpStr(int allowedResolutionLevel) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001694 switch (allowedResolutionLevel) {
Wei Wangb86334f2018-07-03 16:33:24 -07001695 case RESOLUTION_LEVEL_COARSE:
1696 return AppOpsManager.OPSTR_COARSE_LOCATION;
1697 case RESOLUTION_LEVEL_FINE:
1698 return AppOpsManager.OPSTR_FINE_LOCATION;
1699 case RESOLUTION_LEVEL_NONE:
1700 // The client is not allowed to get any location, so both FINE and COARSE ops will
1701 // be denied. Pick the most restrictive one to be safe.
1702 return AppOpsManager.OPSTR_FINE_LOCATION;
1703 default:
1704 // Use the most restrictive ops if not sure.
1705 return AppOpsManager.OPSTR_FINE_LOCATION;
1706 }
1707 }
1708
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001709 private boolean reportLocationAccessNoThrow(
David Christieb870dbf2015-06-22 12:42:53 -07001710 int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001711 int op = resolutionLevelToOp(allowedResolutionLevel);
1712 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001713 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1714 return false;
1715 }
1716 }
David Christieb870dbf2015-06-22 12:42:53 -07001717
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001718 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001719 }
1720
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001721 private boolean checkLocationAccess(int pid, int uid, String packageName,
1722 int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001723 int op = resolutionLevelToOp(allowedResolutionLevel);
1724 if (op >= 0) {
Wei Wangdd070f22018-06-21 11:29:40 -07001725 if (mAppOps.noteOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001726 return false;
1727 }
1728 }
David Christieb870dbf2015-06-22 12:42:53 -07001729
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001730 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001731 }
1732
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001733 /**
Maggie91e630c2018-01-24 17:31:46 -08001734 * Returns all providers by name, including passive and the ones that are not permitted to
1735 * be accessed by the calling activity or are currently disabled, but excluding fused.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001736 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001737 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001738 public List<String> getAllProviders() {
Maggie91e630c2018-01-24 17:31:46 -08001739 ArrayList<String> out;
1740 synchronized (mLock) {
1741 out = new ArrayList<>(mProviders.size());
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001742 for (LocationProvider provider : mProviders) {
Maggie91e630c2018-01-24 17:31:46 -08001743 String name = provider.getName();
1744 if (LocationManager.FUSED_PROVIDER.equals(name)) {
1745 continue;
1746 }
1747 out.add(name);
1748 }
1749 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001750 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001751 return out;
1752 }
1753
Mike Lockwood03ca2162010-04-01 08:10:09 -07001754 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001755 * Return all providers by name, that match criteria and are optionally
1756 * enabled.
1757 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001758 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001759 @Override
1760 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001761 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001762 ArrayList<String> out;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001763 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07001764 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001765 try {
1766 synchronized (mLock) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001767 out = new ArrayList<>(mProviders.size());
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001768 for (LocationProvider provider : mProviders) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001769 String name = provider.getName();
1770 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001771 continue;
1772 }
Victoria Lease37425c32012-10-16 16:08:48 -07001773 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Maggie2a9409e2018-03-21 11:47:28 -07001774 if (enabledOnly
1775 && !isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001776 continue;
1777 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001778 if (criteria != null
1779 && !android.location.LocationProvider.propertiesMeetCriteria(
Victoria Leaseb711d572012-10-02 13:14:11 -07001780 name, provider.getProperties(), criteria)) {
1781 continue;
1782 }
1783 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001784 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001785 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001786 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001787 } finally {
1788 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001789 }
1790
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001791 if (D) Log.d(TAG, "getProviders()=" + out);
1792 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001793 }
1794
1795 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001796 * Return the name of the best provider given a Criteria object.
1797 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001798 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001799 * has been deprecated as well. So this method now uses
1800 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001801 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001802 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001803 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001804 String result;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001805
1806 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001807 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001808 result = pickBest(providers);
1809 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1810 return result;
1811 }
1812 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001813 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001814 result = pickBest(providers);
1815 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1816 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001817 }
1818
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001819 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + null);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001820 return null;
1821 }
1822
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001823 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -07001824 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001825 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -07001826 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1827 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001828 } else {
1829 return providers.get(0);
1830 }
1831 }
1832
Nick Pellye0fd6932012-07-11 10:26:13 -07001833 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001834 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001835 LocationProvider p = mProvidersByName.get(provider);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001836 if (p == null) {
1837 throw new IllegalArgumentException("provider=" + provider);
1838 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001839
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001840 boolean result = android.location.LocationProvider.propertiesMeetCriteria(
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001841 p.getName(), p.getProperties(), criteria);
1842 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1843 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001844 }
1845
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001846 private void updateProvidersSettingsLocked() {
1847 for (LocationProvider p : mProviders) {
1848 p.setSettingsEnabled(isAllowedByUserSettingsLockedForUser(p.getName(), mCurrentUserId));
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001849 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001850
1851 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1852 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001853 }
1854
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001855 private void updateProviderListenersLocked(String provider) {
1856 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001857 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001858
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001859 boolean enabled = p.isEnabled();
1860
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001861 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001862
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001863 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1864 if (records != null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001865 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001866 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001867 // Sends a notification message to the receiver
1868 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1869 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001870 deadReceivers = new ArrayList<>();
Victoria Leaseb711d572012-10-02 13:14:11 -07001871 }
1872 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001873 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001874 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001875 }
1876 }
1877
1878 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001879 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001880 removeUpdatesLocked(deadReceivers.get(i));
1881 }
1882 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001883
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001884 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001885 }
1886
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001887 private void applyRequirementsLocked(String provider) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001888 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001889 if (p == null) return;
1890
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001891 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001892 WorkSource worksource = new WorkSource();
1893 ProviderRequest providerRequest = new ProviderRequest();
1894
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001895 ContentResolver resolver = mContext.getContentResolver();
1896 long backgroundThrottleInterval = Settings.Global.getLong(
1897 resolver,
1898 Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
1899 DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
1900
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001901 if (p.isEnabled() && records != null && !records.isEmpty()) {
1902 // initialize the low power mode to true and set to false if any of the records requires
1903 providerRequest.lowPowerMode = true;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001904 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001905 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
David Christieb870dbf2015-06-22 12:42:53 -07001906 if (checkLocationAccess(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001907 record.mReceiver.mIdentity.mPid,
1908 record.mReceiver.mIdentity.mUid,
1909 record.mReceiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001910 record.mReceiver.mAllowedResolutionLevel)) {
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001911 LocationRequest locationRequest = record.mRealRequest;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001912 long interval = locationRequest.getInterval();
1913
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001914 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001915 if (!record.mIsForegroundUid) {
1916 interval = Math.max(interval, backgroundThrottleInterval);
1917 }
1918 if (interval != locationRequest.getInterval()) {
1919 locationRequest = new LocationRequest(locationRequest);
1920 locationRequest.setInterval(interval);
1921 }
1922 }
1923
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001924 record.mRequest = locationRequest;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001925 providerRequest.locationRequests.add(locationRequest);
gomo48f1a642017-11-10 20:35:46 -08001926 if (!locationRequest.isLowPowerMode()) {
1927 providerRequest.lowPowerMode = false;
1928 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001929 if (interval < providerRequest.interval) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001930 providerRequest.reportLocation = true;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001931 providerRequest.interval = interval;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001932 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001933 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001934 }
1935 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001936
1937 if (providerRequest.reportLocation) {
1938 // calculate who to blame for power
1939 // This is somewhat arbitrary. We pick a threshold interval
1940 // that is slightly higher that the minimum interval, and
1941 // spread the blame across all applications with a request
1942 // under that threshold.
1943 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1944 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001945 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001946 LocationRequest locationRequest = record.mRequest;
Svet Ganove998c732016-06-10 00:12:38 -07001947
1948 // Don't assign battery blame for update records whose
1949 // client has no permission to receive location data.
1950 if (!providerRequest.locationRequests.contains(locationRequest)) {
1951 continue;
1952 }
1953
Victoria Leaseb711d572012-10-02 13:14:11 -07001954 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07001955 if (record.mReceiver.mWorkSource != null
Narayan Kamath32684dd2018-01-08 17:32:51 +00001956 && isValidWorkSource(record.mReceiver.mWorkSource)) {
David Christie82edc9b2013-07-19 11:31:42 -07001957 worksource.add(record.mReceiver.mWorkSource);
1958 } else {
Narayan Kamath32684dd2018-01-08 17:32:51 +00001959 // Assign blame to caller if there's no WorkSource associated with
1960 // the request or if it's invalid.
David Christie82edc9b2013-07-19 11:31:42 -07001961 worksource.add(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001962 record.mReceiver.mIdentity.mUid,
1963 record.mReceiver.mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07001964 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001965 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001966 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001967 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001968 }
1969 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001970
1971 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1972 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001973 }
1974
Narayan Kamath32684dd2018-01-08 17:32:51 +00001975 /**
1976 * Whether a given {@code WorkSource} associated with a Location request is valid.
1977 */
1978 private static boolean isValidWorkSource(WorkSource workSource) {
1979 if (workSource.size() > 0) {
1980 // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
1981 // by tags.
1982 return workSource.getName(0) != null;
1983 } else {
1984 // For now, make sure callers have supplied an attribution tag for use with
1985 // AppOpsManager. This might be relaxed in the future.
1986 final ArrayList<WorkChain> workChains = workSource.getWorkChains();
1987 return workChains != null && !workChains.isEmpty() &&
1988 workChains.get(0).getAttributionTag() != null;
1989 }
1990 }
1991
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001992 @Override
1993 public String[] getBackgroundThrottlingWhitelist() {
1994 synchronized (mLock) {
1995 return mBackgroundThrottlePackageWhitelist.toArray(
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001996 new String[0]);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001997 }
1998 }
1999
2000 private void updateBackgroundThrottlingWhitelistLocked() {
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08002001 String setting = Settings.Global.getString(
gomo48f1a642017-11-10 20:35:46 -08002002 mContext.getContentResolver(),
2003 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08002004 if (setting == null) {
2005 setting = "";
2006 }
2007
2008 mBackgroundThrottlePackageWhitelist.clear();
2009 mBackgroundThrottlePackageWhitelist.addAll(
gomo48f1a642017-11-10 20:35:46 -08002010 SystemConfig.getInstance().getAllowUnthrottledLocation());
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08002011 mBackgroundThrottlePackageWhitelist.addAll(
gomo48f1a642017-11-10 20:35:46 -08002012 Arrays.asList(setting.split(",")));
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08002013 }
2014
Wei Wangdd070f22018-06-21 11:29:40 -07002015 private void updateLastLocationMaxAgeLocked() {
2016 mLastLocationMaxAgeMs =
2017 Settings.Global.getLong(
2018 mContext.getContentResolver(),
2019 Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
2020 DEFAULT_LAST_LOCATION_MAX_AGE_MS);
2021 }
2022
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002023 private boolean isThrottlingExemptLocked(Identity identity) {
2024 if (identity.mUid == Process.SYSTEM_UID) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002025 return true;
2026 }
2027
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002028 if (mBackgroundThrottlePackageWhitelist.contains(identity.mPackageName)) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002029 return true;
2030 }
2031
2032 for (LocationProviderProxy provider : mProxyProviders) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002033 if (identity.mPackageName.equals(provider.getConnectedPackageName())) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002034 return true;
2035 }
2036 }
2037
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002038 return false;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002039 }
2040
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002041 private class UpdateRecord {
2042 final String mProvider;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002043 private final LocationRequest mRealRequest; // original request from client
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002044 LocationRequest mRequest; // possibly throttled version of the request
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002045 private final Receiver mReceiver;
2046 private boolean mIsForegroundUid;
2047 private Location mLastFixBroadcast;
2048 private long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002049
2050 /**
2051 * Note: must be constructed with lock held.
2052 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002053 private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 mProvider = provider;
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002055 mRealRequest = request;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002056 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002057 mReceiver = receiver;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002058 mIsForegroundUid = isImportanceForeground(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002059 mActivityManager.getPackageImportance(mReceiver.mIdentity.mPackageName));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002060
2061 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2062 if (records == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002063 records = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002064 mRecordsByProvider.put(provider, records);
2065 }
2066 if (!records.contains(this)) {
2067 records.add(this);
2068 }
David Christie2ff96af2014-01-30 16:09:37 -08002069
2070 // Update statistics for historical location requests by package/provider
2071 mRequestStatistics.startRequesting(
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002072 mReceiver.mIdentity.mPackageName, provider, request.getInterval(),
2073 mIsForegroundUid);
2074 }
2075
2076 /**
2077 * Method to be called when record changes foreground/background
2078 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002079 private void updateForeground(boolean isForeground) {
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002080 mIsForegroundUid = isForeground;
2081 mRequestStatistics.updateForeground(
2082 mReceiver.mIdentity.mPackageName, mProvider, isForeground);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002083 }
2084
2085 /**
David Christie2ff96af2014-01-30 16:09:37 -08002086 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002087 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002088 private void disposeLocked(boolean removeReceiver) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002089 mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
David Christie2ff96af2014-01-30 16:09:37 -08002090
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002091 // remove from mRecordsByProvider
2092 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
2093 if (globalRecords != null) {
2094 globalRecords.remove(this);
2095 }
2096
2097 if (!removeReceiver) return; // the caller will handle the rest
2098
2099 // remove from Receiver#mUpdateRecords
2100 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002101 receiverRecords.remove(this.mProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002102
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002103 // and also remove the Receiver if it has no more update records
2104 if (receiverRecords.size() == 0) {
2105 removeUpdatesLocked(mReceiver);
Mike Lockwood3a76fd62009-09-01 07:26:56 -04002106 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002107 }
2108
2109 @Override
2110 public String toString() {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002111 return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
gomo48f1a642017-11-10 20:35:46 -08002112 + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground"
2113 : " background")
Wyatt Riley19adc022018-05-22 13:30:51 -07002114 + ")" + " " + mRealRequest + " "
2115 + mReceiver.mWorkSource + "]";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002116 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002117 }
2118
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002119 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07002120 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002121 IBinder binder = listener.asBinder();
2122 Receiver receiver = mReceivers.get(binder);
2123 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002124 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
2125 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002126 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002127 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002128 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002129 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002130 return null;
2131 }
Wen Jingcb3ab222014-03-27 13:42:59 +08002132 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002133 }
2134 return receiver;
2135 }
2136
David Christie82edc9b2013-07-19 11:31:42 -07002137 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07002138 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002139 Receiver receiver = mReceivers.get(intent);
2140 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002141 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
2142 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002143 mReceivers.put(intent, receiver);
2144 }
2145 return receiver;
2146 }
2147
Victoria Lease37425c32012-10-16 16:08:48 -07002148 /**
2149 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
2150 * and consistency requirements.
2151 *
2152 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07002153 * @return a version of request that meets the given resolution and consistency requirements
2154 * @hide
2155 */
gomo48f1a642017-11-10 20:35:46 -08002156 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel,
2157 boolean callerHasLocationHardwarePermission) {
Victoria Lease37425c32012-10-16 16:08:48 -07002158 LocationRequest sanitizedRequest = new LocationRequest(request);
gomo48f1a642017-11-10 20:35:46 -08002159 if (!callerHasLocationHardwarePermission) {
2160 // allow setting low power mode only for callers with location hardware permission
2161 sanitizedRequest.setLowPowerMode(false);
2162 }
Victoria Lease37425c32012-10-16 16:08:48 -07002163 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
2164 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002165 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07002166 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07002167 break;
2168 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07002169 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07002170 break;
2171 }
2172 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07002173 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2174 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002175 }
Victoria Lease37425c32012-10-16 16:08:48 -07002176 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2177 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002178 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002179 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002180 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07002181 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002182 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002183 }
Victoria Lease37425c32012-10-16 16:08:48 -07002184 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002185 }
2186
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002187 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07002188 if (packageName == null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002189 throw new SecurityException("invalid package name: " + null);
Nick Pellye0fd6932012-07-11 10:26:13 -07002190 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002191 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07002192 String[] packages = mPackageManager.getPackagesForUid(uid);
2193 if (packages == null) {
2194 throw new SecurityException("invalid UID " + uid);
2195 }
2196 for (String pkg : packages) {
2197 if (packageName.equals(pkg)) return;
2198 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002199 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002200 }
2201
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002202 private void checkPendingIntent(PendingIntent intent) {
2203 if (intent == null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002204 throw new IllegalArgumentException("invalid pending intent: " + null);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07002205 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002206 }
2207
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002208 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
David Christie40e57822013-07-30 11:36:48 -07002209 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002210 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002211 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002212 } else if (intent != null && listener != null) {
2213 throw new IllegalArgumentException("cannot register both listener and intent");
2214 } else if (intent != null) {
2215 checkPendingIntent(intent);
David Christie40e57822013-07-30 11:36:48 -07002216 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002217 } else {
David Christie40e57822013-07-30 11:36:48 -07002218 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002219 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07002220 }
2221
Nick Pellye0fd6932012-07-11 10:26:13 -07002222 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002223 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
2224 PendingIntent intent, String packageName) {
2225 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2226 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002227 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2228 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2229 request.getProvider());
David Christie82edc9b2013-07-19 11:31:42 -07002230 WorkSource workSource = request.getWorkSource();
Narayan Kamath32684dd2018-01-08 17:32:51 +00002231 if (workSource != null && !workSource.isEmpty()) {
David Christie40e57822013-07-30 11:36:48 -07002232 checkDeviceStatsAllowed();
2233 }
2234 boolean hideFromAppOps = request.getHideFromAppOps();
2235 if (hideFromAppOps) {
2236 checkUpdateAppOpsAllowed();
David Christie82edc9b2013-07-19 11:31:42 -07002237 }
gomo48f1a642017-11-10 20:35:46 -08002238 boolean callerHasLocationHardwarePermission =
2239 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
Maggieaa080f92018-01-04 15:35:11 -08002240 == PERMISSION_GRANTED;
gomo48f1a642017-11-10 20:35:46 -08002241 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
2242 callerHasLocationHardwarePermission);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002243
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002244 final int pid = Binder.getCallingPid();
2245 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002246 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002247 long identity = Binder.clearCallingIdentity();
2248 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002249 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
2250 // a location.
David Christieb870dbf2015-06-22 12:42:53 -07002251 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002252
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002253 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002254 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
David Christie40e57822013-07-30 11:36:48 -07002255 packageName, workSource, hideFromAppOps);
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002256 requestLocationUpdatesLocked(sanitizedRequest, recevier, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04002257 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002258 } finally {
2259 Binder.restoreCallingIdentity(identity);
2260 }
2261 }
2262
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002263 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002264 int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002265 // Figure out the provider. Either its explicitly request (legacy use cases), or
2266 // use the fused provider
2267 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2268 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07002269 if (name == null) {
2270 throw new IllegalArgumentException("provider name must not be null");
2271 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07002272
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002273 LocationProvider provider = mProvidersByName.get(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002274 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07002275 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002276 }
2277
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002278 UpdateRecord record = new UpdateRecord(name, request, receiver);
gomo48f1a642017-11-10 20:35:46 -08002279 if (D) {
2280 Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
2281 + " " + name + " " + request + " from " + packageName + "(" + uid + " "
2282 + (record.mIsForegroundUid ? "foreground" : "background")
2283 + (isThrottlingExemptLocked(receiver.mIdentity)
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002284 ? " [whitelisted]" : "") + ")");
gomo48f1a642017-11-10 20:35:46 -08002285 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002286
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002287 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
2288 if (oldRecord != null) {
2289 oldRecord.disposeLocked(false);
2290 }
2291
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002292 if (provider.isEnabled()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002293 applyRequirementsLocked(name);
2294 } else {
2295 // Notify the listener that updates are currently disabled
2296 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002297 }
David Christie0b837452013-07-29 16:02:13 -07002298 // Update the monitoring here just in case multiple location requests were added to the
2299 // same receiver (this request may be high power and the initial might not have been).
2300 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002301 }
2302
Nick Pellye0fd6932012-07-11 10:26:13 -07002303 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002304 public void removeUpdates(ILocationListener listener, PendingIntent intent,
2305 String packageName) {
2306 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002307
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002308 final int pid = Binder.getCallingPid();
2309 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002310
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002311 synchronized (mLock) {
David Christie40e57822013-07-30 11:36:48 -07002312 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002313 packageName, null, false);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002314
2315 // providers may use public location API's, need to clear identity
2316 long identity = Binder.clearCallingIdentity();
2317 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002318 removeUpdatesLocked(receiver);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002319 } finally {
2320 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002321 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002322 }
2323 }
2324
2325 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08002326 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002327
2328 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
2329 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
2330 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07002331 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002332 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002333 }
2334
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07002335 receiver.updateMonitoring(false);
2336
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002337 // Record which providers were associated with this listener
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002338 HashSet<String> providers = new HashSet<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002339 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
2340 if (oldRecords != null) {
2341 // Call dispose() on the obsolete update records.
2342 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08002343 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002344 record.disposeLocked(false);
2345 }
2346 // Accumulate providers
2347 providers.addAll(oldRecords.keySet());
2348 }
2349
2350 // update provider
2351 for (String provider : providers) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002352 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002353 }
2354 }
2355
Dianne Hackbornc2293022013-02-06 23:14:49 -08002356 private void applyAllProviderRequirementsLocked() {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002357 for (LocationProvider p : mProviders) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08002358 applyRequirementsLocked(p.getName());
2359 }
2360 }
2361
Nick Pellye0fd6932012-07-11 10:26:13 -07002362 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07002363 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002364 if (D) Log.d(TAG, "getLastLocation: " + request);
2365 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002366 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07002367 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002368 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2369 request.getProvider());
2370 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07002371
David Christieb870dbf2015-06-22 12:42:53 -07002372 final int pid = Binder.getCallingPid();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002373 final int uid = Binder.getCallingUid();
2374 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07002375 try {
2376 if (mBlacklist.isBlacklisted(packageName)) {
gomo48f1a642017-11-10 20:35:46 -08002377 if (D) {
2378 Log.d(TAG, "not returning last loc for blacklisted app: " +
2379 packageName);
2380 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002381 return null;
2382 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002383
David Christieb870dbf2015-06-22 12:42:53 -07002384 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08002385 if (D) {
2386 Log.d(TAG, "not returning last loc for no op app: " +
2387 packageName);
2388 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002389 return null;
2390 }
2391
Victoria Leaseb711d572012-10-02 13:14:11 -07002392 synchronized (mLock) {
2393 // Figure out the provider. Either its explicitly request (deprecated API's),
2394 // or use the fused provider
2395 String name = request.getProvider();
2396 if (name == null) name = LocationManager.FUSED_PROVIDER;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002397 LocationProvider provider = mProvidersByName.get(name);
Victoria Leaseb711d572012-10-02 13:14:11 -07002398 if (provider == null) return null;
2399
Maggie2a9409e2018-03-21 11:47:28 -07002400 if (!isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07002401
David Christie1b9b7b12013-04-15 15:31:11 -07002402 Location location;
2403 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2404 // Make sure that an app with coarse permissions can't get frequent location
2405 // updates by calling LocationManager.getLastKnownLocation repeatedly.
2406 location = mLastLocationCoarseInterval.get(name);
2407 } else {
2408 location = mLastLocation.get(name);
2409 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002410 if (location == null) {
2411 return null;
2412 }
Wei Wangdd070f22018-06-21 11:29:40 -07002413
2414 // Don't return stale location to apps with foreground-only location permission.
Wei Wangb86334f2018-07-03 16:33:24 -07002415 String op = resolutionLevelToOpStr(allowedResolutionLevel);
Wei Wangdd070f22018-06-21 11:29:40 -07002416 long locationAgeMs = SystemClock.elapsedRealtime() -
2417 location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
2418 if ((locationAgeMs > mLastLocationMaxAgeMs)
2419 && (mAppOps.unsafeCheckOp(op, uid, packageName)
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002420 == AppOpsManager.MODE_FOREGROUND)) {
Wei Wangdd070f22018-06-21 11:29:40 -07002421 return null;
2422 }
2423
Victoria Lease37425c32012-10-16 16:08:48 -07002424 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
gomo48f1a642017-11-10 20:35:46 -08002425 Location noGPSLocation = location.getExtraLocation(
2426 Location.EXTRA_NO_GPS_LOCATION);
Victoria Leaseb711d572012-10-02 13:14:11 -07002427 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08002428 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07002429 }
Victoria Lease37425c32012-10-16 16:08:48 -07002430 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08002431 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07002432 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002433 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002434 return null;
2435 } finally {
2436 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002437 }
2438 }
2439
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002440 /**
2441 * Provides an interface to inject and set the last location if location is not available
2442 * currently.
2443 *
2444 * This helps in cases where the product (Cars for example) has saved the last known location
2445 * before powering off. This interface lets the client inject the saved location while the GPS
2446 * chipset is getting its first fix, there by improving user experience.
2447 *
2448 * @param location - Location object to inject
2449 * @return true if update was successful, false if not
2450 */
2451 @Override
2452 public boolean injectLocation(Location location) {
2453 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
2454 "Location Hardware permission not granted to inject location");
2455 mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
2456 "Access Fine Location permission not granted to inject Location");
2457
2458 if (location == null) {
2459 if (D) {
2460 Log.d(TAG, "injectLocation(): called with null location");
2461 }
2462 return false;
2463 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002464 LocationProvider p = null;
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002465 String provider = location.getProvider();
2466 if (provider != null) {
2467 p = mProvidersByName.get(provider);
2468 }
2469 if (p == null) {
2470 if (D) {
2471 Log.d(TAG, "injectLocation(): unknown provider");
2472 }
2473 return false;
2474 }
2475 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002476 if (!isAllowedByUserSettingsLockedForUser(provider, mCurrentUserId)) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002477 if (D) {
2478 Log.d(TAG, "Location disabled in Settings for current user:" + mCurrentUserId);
2479 }
2480 return false;
2481 } else {
2482 // NOTE: If last location is already available, location is not injected. If
2483 // provider's normal source (like a GPS chipset) have already provided an output,
2484 // there is no need to inject this location.
2485 if (mLastLocation.get(provider) == null) {
2486 updateLastLocationLocked(location, provider);
2487 } else {
2488 if (D) {
2489 Log.d(TAG, "injectLocation(): Location exists. Not updating");
2490 }
2491 return false;
2492 }
2493 }
2494 }
2495 return true;
2496 }
2497
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002498 @Override
2499 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
2500 String packageName) {
2501 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002502 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2503 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002504 checkPendingIntent(intent);
2505 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002506 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2507 request.getProvider());
gomo48f1a642017-11-10 20:35:46 -08002508 // Require that caller can manage given document
2509 boolean callerHasLocationHardwarePermission =
2510 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
Maggieaa080f92018-01-04 15:35:11 -08002511 == PERMISSION_GRANTED;
gomo48f1a642017-11-10 20:35:46 -08002512 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
2513 callerHasLocationHardwarePermission);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002514
Victoria Lease37425c32012-10-16 16:08:48 -07002515 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002516
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002517 // geo-fence manager uses the public location API, need to clear identity
2518 int uid = Binder.getCallingUid();
Xiaohui Chena4490622015-09-22 15:29:31 -07002519 // TODO: http://b/23822629
2520 if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
Victoria Lease56e675b2012-11-05 19:25:06 -08002521 // temporary measure until geofences work for secondary users
2522 Log.w(TAG, "proximity alerts are currently available only to the primary user");
2523 return;
2524 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002525 long identity = Binder.clearCallingIdentity();
2526 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002527 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
2528 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002529 } finally {
2530 Binder.restoreCallingIdentity(identity);
2531 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002532 }
2533
2534 @Override
2535 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002536 checkPendingIntent(intent);
2537 checkPackageName(packageName);
2538
2539 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
2540
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002541 // geo-fence manager uses the public location API, need to clear identity
2542 long identity = Binder.clearCallingIdentity();
2543 try {
2544 mGeofenceManager.removeFence(geofence, intent);
2545 } finally {
2546 Binder.restoreCallingIdentity(identity);
2547 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002548 }
2549
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002550 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002551 public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002552 if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09002553 return false;
2554 }
2555
Anil Admal75b9fd62018-11-28 11:22:50 -08002556 // TODO(b/120449926): The GNSS status listeners should be handled similar to the GNSS
2557 // measurements listeners.
2558 return mGnssStatusProvider.addListener(callback, Binder.getCallingUid(), packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002559 }
2560
Nick Pellye0fd6932012-07-11 10:26:13 -07002561 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002562 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002563 mGnssStatusProvider.removeListener(callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002564 }
2565
Nick Pellye0fd6932012-07-11 10:26:13 -07002566 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002567 public boolean addGnssMeasurementsListener(
gomo48f1a642017-11-10 20:35:46 -08002568 IGnssMeasurementsListener listener, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002569 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07002570 return false;
2571 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002572
2573 synchronized (mLock) {
2574 Identity callerIdentity
2575 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Anil Admal75b9fd62018-11-28 11:22:50 -08002576 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002577 mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002578 long identity = Binder.clearCallingIdentity();
2579 try {
2580 if (isThrottlingExemptLocked(callerIdentity)
2581 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002582 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002583 return mGnssMeasurementsProvider.addListener(listener,
2584 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002585 }
2586 } finally {
2587 Binder.restoreCallingIdentity(identity);
2588 }
2589
2590 return true;
2591 }
destradaaea8a8a62014-06-23 18:19:03 -07002592 }
2593
2594 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002595 public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002596 if (mGnssMeasurementsProvider == null) {
2597 return;
2598 }
2599
2600 synchronized (mLock) {
2601 mGnssMeasurementsListeners.remove(listener.asBinder());
2602 mGnssMeasurementsProvider.removeListener(listener);
Wei Liu5241a4c2015-05-11 14:00:36 -07002603 }
destradaaea8a8a62014-06-23 18:19:03 -07002604 }
2605
2606 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002607 public boolean addGnssNavigationMessageListener(
2608 IGnssNavigationMessageListener listener,
destradaa4b3e3932014-07-21 18:01:47 -07002609 String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002610 if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07002611 return false;
2612 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002613
2614 synchronized (mLock) {
2615 Identity callerIdentity
gomo48f1a642017-11-10 20:35:46 -08002616 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Anil Admal75b9fd62018-11-28 11:22:50 -08002617 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002618 mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002619 long identity = Binder.clearCallingIdentity();
2620 try {
2621 if (isThrottlingExemptLocked(callerIdentity)
2622 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002623 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002624 return mGnssNavigationMessageProvider.addListener(listener,
2625 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002626 }
2627 } finally {
2628 Binder.restoreCallingIdentity(identity);
2629 }
2630
2631 return true;
2632 }
destradaa4b3e3932014-07-21 18:01:47 -07002633 }
2634
2635 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002636 public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
2637 if (mGnssNavigationMessageProvider != null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002638 synchronized (mLock) {
Wyatt Riley11cc7492018-01-17 08:48:27 -08002639 mGnssNavigationMessageListeners.remove(listener.asBinder());
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002640 mGnssNavigationMessageProvider.removeListener(listener);
2641 }
Wei Liu5241a4c2015-05-11 14:00:36 -07002642 }
destradaa4b3e3932014-07-21 18:01:47 -07002643 }
2644
2645 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002646 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002647 if (provider == null) {
2648 // throw NullPointerException to remain compatible with previous implementation
2649 throw new NullPointerException();
2650 }
Victoria Lease37425c32012-10-16 16:08:48 -07002651 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2652 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002653
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002654 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04002655 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
Maggieaa080f92018-01-04 15:35:11 -08002656 != PERMISSION_GRANTED)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002657 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2658 }
2659
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002660 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002661 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002662 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07002663
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002664 p.sendExtraCommand(command, extras);
2665 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002666 }
2667 }
2668
Nick Pellye0fd6932012-07-11 10:26:13 -07002669 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002670 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07002671 if (Binder.getCallingUid() != Process.myUid()) {
2672 throw new SecurityException(
2673 "calling sendNiResponse from outside of the system is not allowed");
2674 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04002675 try {
2676 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002677 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002678 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04002679 return false;
2680 }
2681 }
2682
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002683 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002684 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11002685 * @throws SecurityException if the provider is not allowed to be
gomo48f1a642017-11-10 20:35:46 -08002686 * accessed by the caller
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002687 */
Nick Pellye0fd6932012-07-11 10:26:13 -07002688 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002689 public ProviderProperties getProviderProperties(String provider) {
Victoria Lease37425c32012-10-16 16:08:48 -07002690 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2691 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002692
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002693 LocationProvider p;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002694 synchronized (mLock) {
2695 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002696 }
2697
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002698 if (p == null) return null;
2699 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002700 }
2701
Jason Monkb71218a2015-06-17 14:44:39 -04002702 /**
2703 * @return null if the provider does not exist
2704 * @throws SecurityException if the provider is not allowed to be
gomo48f1a642017-11-10 20:35:46 -08002705 * accessed by the caller
Jason Monkb71218a2015-06-17 14:44:39 -04002706 */
2707 @Override
2708 public String getNetworkProviderPackage() {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002709 LocationProvider p;
Jason Monkb71218a2015-06-17 14:44:39 -04002710 synchronized (mLock) {
Jason Monkb71218a2015-06-17 14:44:39 -04002711 p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
2712 }
2713
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002714 if (p == null) {
2715 return null;
2716 }
2717 if (p.mProvider instanceof LocationProviderProxy) {
2718 return ((LocationProviderProxy) p.mProvider).getConnectedPackageName();
Jason Monkb71218a2015-06-17 14:44:39 -04002719 }
2720 return null;
2721 }
2722
Wei Wang980b7c22018-12-06 17:53:00 -08002723 @Override
2724 public void setLocationControllerExtraPackage(String packageName) {
2725 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2726 Manifest.permission.LOCATION_HARDWARE + " permission required");
2727 synchronized (mLock) {
2728 mLocationControllerExtraPackage = packageName;
2729 }
2730 }
2731
2732 @Override
2733 public String getLocationControllerExtraPackage() {
2734 synchronized (mLock) {
2735 return mLocationControllerExtraPackage;
2736 }
2737 }
2738
2739 @Override
2740 public void setLocationControllerExtraPackageEnabled(boolean enabled) {
2741 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2742 Manifest.permission.LOCATION_HARDWARE + " permission required");
2743 synchronized (mLock) {
2744 mLocationControllerExtraPackageEnabled = enabled;
2745 }
2746 }
2747
2748 @Override
2749 public boolean isLocationControllerExtraPackageEnabled() {
2750 synchronized (mLock) {
2751 return mLocationControllerExtraPackageEnabled
2752 && (mLocationControllerExtraPackage != null);
2753 }
2754 }
2755
Maggieaa080f92018-01-04 15:35:11 -08002756 /**
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002757 * Returns the current location enabled/disabled status for a user
Maggie2a9409e2018-03-21 11:47:28 -07002758 *
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002759 * @param userId the id of the user
2760 * @return true if location is enabled
Maggie2a9409e2018-03-21 11:47:28 -07002761 */
2762 @Override
2763 public boolean isLocationEnabledForUser(int userId) {
2764 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2765 checkInteractAcrossUsersPermission(userId);
2766
2767 long identity = Binder.clearCallingIdentity();
2768 try {
2769 synchronized (mLock) {
2770 final String allowedProviders = Settings.Secure.getStringForUser(
2771 mContext.getContentResolver(),
2772 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
2773 userId);
2774 if (allowedProviders == null) {
2775 return false;
2776 }
2777 final List<String> providerList = Arrays.asList(allowedProviders.split(","));
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002778 for (String provider : mRealProviders.keySet()) {
Maggie2a9409e2018-03-21 11:47:28 -07002779 if (provider.equals(LocationManager.PASSIVE_PROVIDER)
2780 || provider.equals(LocationManager.FUSED_PROVIDER)) {
2781 continue;
2782 }
2783 if (providerList.contains(provider)) {
2784 return true;
2785 }
2786 }
2787 return false;
2788 }
2789 } finally {
2790 Binder.restoreCallingIdentity(identity);
2791 }
2792 }
2793
2794 /**
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002795 * Enable or disable location for a user
Maggie2a9409e2018-03-21 11:47:28 -07002796 *
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002797 * @param enabled true to enable location, false to disable location
2798 * @param userId the id of the user
Maggie2a9409e2018-03-21 11:47:28 -07002799 */
2800 @Override
2801 public void setLocationEnabledForUser(boolean enabled, int userId) {
2802 mContext.enforceCallingPermission(
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002803 android.Manifest.permission.WRITE_SECURE_SETTINGS,
2804 "Requires WRITE_SECURE_SETTINGS permission");
Maggie2a9409e2018-03-21 11:47:28 -07002805
2806 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2807 checkInteractAcrossUsersPermission(userId);
2808
2809 long identity = Binder.clearCallingIdentity();
2810 try {
2811 synchronized (mLock) {
2812 final Set<String> allRealProviders = mRealProviders.keySet();
2813 // Update all providers on device plus gps and network provider when disabling
2814 // location
2815 Set<String> allProvidersSet = new ArraySet<>(allRealProviders.size() + 2);
2816 allProvidersSet.addAll(allRealProviders);
2817 // When disabling location, disable gps and network provider that could have been
2818 // enabled by location mode api.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002819 if (!enabled) {
Maggie2a9409e2018-03-21 11:47:28 -07002820 allProvidersSet.add(LocationManager.GPS_PROVIDER);
2821 allProvidersSet.add(LocationManager.NETWORK_PROVIDER);
2822 }
2823 if (allProvidersSet.isEmpty()) {
2824 return;
2825 }
2826 // to ensure thread safety, we write the provider name with a '+' or '-'
2827 // and let the SettingsProvider handle it rather than reading and modifying
2828 // the list of enabled providers.
2829 final String prefix = enabled ? "+" : "-";
2830 StringBuilder locationProvidersAllowed = new StringBuilder();
2831 for (String provider : allProvidersSet) {
2832 if (provider.equals(LocationManager.PASSIVE_PROVIDER)
2833 || provider.equals(LocationManager.FUSED_PROVIDER)) {
2834 continue;
2835 }
2836 locationProvidersAllowed.append(prefix);
2837 locationProvidersAllowed.append(provider);
2838 locationProvidersAllowed.append(",");
2839 }
2840 // Remove the trailing comma
2841 locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
2842 Settings.Secure.putStringForUser(
2843 mContext.getContentResolver(),
2844 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
2845 locationProvidersAllowed.toString(),
2846 userId);
2847 }
2848 } finally {
2849 Binder.restoreCallingIdentity(identity);
2850 }
2851 }
2852
2853 /**
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002854 * Returns the current enabled/disabled status of a location provider and user
Maggie2a9409e2018-03-21 11:47:28 -07002855 *
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002856 * @param providerName name of the provider
2857 * @param userId the id of the user
2858 * @return true if the provider exists and is enabled
Maggie2a9409e2018-03-21 11:47:28 -07002859 */
2860 @Override
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002861 public boolean isProviderEnabledForUser(String providerName, int userId) {
Maggie2a9409e2018-03-21 11:47:28 -07002862 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2863 checkInteractAcrossUsersPermission(userId);
2864
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002865 if (!isLocationEnabledForUser(userId)) {
2866 return false;
2867 }
2868
Maggie2a9409e2018-03-21 11:47:28 -07002869 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2870 // so we discourage its use
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002871 if (LocationManager.FUSED_PROVIDER.equals(providerName)) return false;
Maggie2a9409e2018-03-21 11:47:28 -07002872
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002873 long identity = Binder.clearCallingIdentity();
2874 try {
2875 LocationProvider provider;
2876 synchronized (mLock) {
2877 provider = mProvidersByName.get(providerName);
2878 }
2879 return provider != null && provider.isEnabled();
2880 } finally {
2881 Binder.restoreCallingIdentity(identity);
Maggie2a9409e2018-03-21 11:47:28 -07002882 }
2883 }
2884
2885 /**
2886 * Enable or disable a single location provider.
2887 *
2888 * @param provider name of the provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002889 * @param enabled true to enable the provider. False to disable the provider
2890 * @param userId the id of the user to set
Maggie2a9409e2018-03-21 11:47:28 -07002891 * @return true if the value was set, false on errors
2892 */
2893 @Override
2894 public boolean setProviderEnabledForUser(String provider, boolean enabled, int userId) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002895 return false;
Maggieaa080f92018-01-04 15:35:11 -08002896 }
2897
2898 /**
Maggie2a9409e2018-03-21 11:47:28 -07002899 * Method for checking INTERACT_ACROSS_USERS permission if specified user id is not the same as
2900 * current user id
2901 *
2902 * @param userId the user id to get or set value
2903 */
2904 private void checkInteractAcrossUsersPermission(int userId) {
2905 int uid = Binder.getCallingUid();
2906 if (UserHandle.getUserId(uid) != userId) {
2907 if (ActivityManager.checkComponentPermission(
2908 android.Manifest.permission.INTERACT_ACROSS_USERS, uid, -1, true)
2909 != PERMISSION_GRANTED) {
2910 throw new SecurityException("Requires INTERACT_ACROSS_USERS permission");
2911 }
2912 }
2913 }
2914
2915 /**
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002916 * Returns "true" if the UID belongs to a bound location provider.
2917 *
2918 * @param uid the uid
2919 * @return true if uid belongs to a bound location provider
2920 */
2921 private boolean isUidALocationProvider(int uid) {
2922 if (uid == Process.SYSTEM_UID) {
2923 return true;
2924 }
2925 if (mGeocodeProvider != null) {
David Christie1f141c12014-05-14 15:11:15 -07002926 if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002927 }
2928 for (LocationProviderProxy proxy : mProxyProviders) {
David Christie1f141c12014-05-14 15:11:15 -07002929 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002930 }
2931 return false;
2932 }
2933
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002934 private void checkCallerIsProvider() {
2935 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
Maggieaa080f92018-01-04 15:35:11 -08002936 == PERMISSION_GRANTED) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002937 return;
2938 }
2939
2940 // Previously we only used the INSTALL_LOCATION_PROVIDER
2941 // check. But that is system or signature
2942 // protection level which is not flexible enough for
2943 // providers installed oustide the system image. So
2944 // also allow providers with a UID matching the
2945 // currently bound package name
2946
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002947 if (isUidALocationProvider(Binder.getCallingUid())) {
2948 return;
2949 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002950
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002951 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2952 "or UID of a currently bound location provider");
2953 }
2954
David Christie1f141c12014-05-14 15:11:15 -07002955 /**
2956 * Returns true if the given package belongs to the given uid.
2957 */
2958 private boolean doesUidHavePackage(int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002959 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002960 return false;
2961 }
David Christie1f141c12014-05-14 15:11:15 -07002962 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2963 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002964 return false;
2965 }
David Christie1f141c12014-05-14 15:11:15 -07002966 for (String name : packageNames) {
2967 if (packageName.equals(name)) {
2968 return true;
2969 }
2970 }
2971 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002972 }
2973
Nick Pellye0fd6932012-07-11 10:26:13 -07002974 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05002975 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002976 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04002977
Nick Pelly2eeeec22012-07-18 13:13:37 -07002978 if (!location.isComplete()) {
2979 Log.w(TAG, "Dropping incomplete location: " + location);
2980 return;
2981 }
2982
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002983 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2984 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05002985 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002986 mLocationHandler.sendMessageAtFrontOfQueue(m);
2987 }
2988
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002989
Laurent Tu75defb62012-11-01 16:21:52 -07002990 private static boolean shouldBroadcastSafe(
2991 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002992 // Always broadcast the first update
2993 if (lastLoc == null) {
2994 return true;
2995 }
2996
Nick Pellyf1be6862012-05-15 10:53:42 -07002997 // Check whether sufficient time has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002998 long minTime = record.mRealRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002999 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
3000 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003001 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003002 return false;
3003 }
3004
3005 // Check whether sufficient distance has been traveled
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003006 double minDistance = record.mRealRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003007 if (minDistance > 0.0) {
3008 if (loc.distanceTo(lastLoc) <= minDistance) {
3009 return false;
3010 }
3011 }
3012
Laurent Tu75defb62012-11-01 16:21:52 -07003013 // Check whether sufficient number of udpates is left
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003014 if (record.mRealRequest.getNumUpdates() <= 0) {
Laurent Tu75defb62012-11-01 16:21:52 -07003015 return false;
3016 }
3017
3018 // Check whether the expiry date has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003019 return record.mRealRequest.getExpireAt() >= now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003020 }
3021
Mike Lockwooda4903f22010-02-17 06:42:23 -05003022 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07003023 if (D) Log.d(TAG, "incoming location: " + location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003024 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05003025 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
Laurent Tu60ec50a2012-10-04 17:00:10 -07003026 // Skip if the provider is unknown.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003027 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003028 if (p == null) return;
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003029 updateLastLocationLocked(location, provider);
3030 // mLastLocation should have been updated from the updateLastLocationLocked call above.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003031 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07003032 if (lastLocation == null) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003033 Log.e(TAG, "handleLocationChangedLocked() updateLastLocation failed");
3034 return;
Mike Lockwood4e50b782009-04-03 08:24:43 -07003035 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003036
David Christie1b9b7b12013-04-15 15:31:11 -07003037 // Update last known coarse interval location if enough time has passed.
3038 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
3039 if (lastLocationCoarseInterval == null) {
3040 lastLocationCoarseInterval = new Location(location);
3041 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
3042 }
3043 long timeDiffNanos = location.getElapsedRealtimeNanos()
3044 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
3045 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
3046 lastLocationCoarseInterval.set(location);
3047 }
3048 // Don't ever return a coarse location that is more recent than the allowed update
3049 // interval (i.e. don't allow an app to keep registering and unregistering for
3050 // location updates to overcome the minimum interval).
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003051 Location noGPSLocation =
David Christie1b9b7b12013-04-15 15:31:11 -07003052 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3053
Laurent Tu60ec50a2012-10-04 17:00:10 -07003054 // Skip if there are no UpdateRecords for this provider.
3055 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
3056 if (records == null || records.size() == 0) return;
3057
Victoria Lease09016ab2012-09-16 12:33:15 -07003058 // Fetch coarse location
3059 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07003060 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003061 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
3062 }
3063
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003064 // Fetch latest status update time
3065 long newStatusUpdateTime = p.getStatusUpdateTime();
3066
David Christie2ff96af2014-01-30 16:09:37 -08003067 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003068 Bundle extras = new Bundle();
3069 int status = p.getStatus(extras);
3070
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003071 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003072 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07003073
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003074 // Broadcast location to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003075 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003076 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07003077 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07003078
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003079 int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
3080 if (!isCurrentProfile(receiverUserId)
3081 && !isUidALocationProvider(receiver.mIdentity.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07003082 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07003083 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07003084 " (current user: " + mCurrentUserId + ", app: " +
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003085 receiver.mIdentity.mPackageName + ")");
Victoria Leaseb711d572012-10-02 13:14:11 -07003086 }
3087 continue;
3088 }
3089
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003090 if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
gomo48f1a642017-11-10 20:35:46 -08003091 if (D) {
3092 Log.d(TAG, "skipping loc update for blacklisted app: " +
3093 receiver.mIdentity.mPackageName);
3094 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07003095 continue;
3096 }
3097
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003098 if (!reportLocationAccessNoThrow(
3099 receiver.mIdentity.mPid,
3100 receiver.mIdentity.mUid,
3101 receiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003102 receiver.mAllowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08003103 if (D) {
3104 Log.d(TAG, "skipping loc update for no op app: " +
3105 receiver.mIdentity.mPackageName);
3106 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003107 continue;
3108 }
3109
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003110 Location notifyLocation;
Victoria Lease37425c32012-10-16 16:08:48 -07003111 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
3112 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003113 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07003114 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003115 }
Victoria Lease09016ab2012-09-16 12:33:15 -07003116 if (notifyLocation != null) {
3117 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07003118 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003119 if (lastLoc == null) {
3120 lastLoc = new Location(notifyLocation);
3121 r.mLastFixBroadcast = lastLoc;
3122 } else {
3123 lastLoc.set(notifyLocation);
3124 }
3125 if (!receiver.callLocationChangedLocked(notifyLocation)) {
3126 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
3127 receiverDead = true;
3128 }
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003129 r.mRealRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003130 }
3131 }
3132
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003133 // TODO: location provider status callbacks have been disabled and deprecated, and are
3134 // guarded behind this setting now. should be removed completely post-Q
3135 if (Settings.Global.getInt(mContext.getContentResolver(),
3136 LOCATION_DISABLE_STATUS_CALLBACKS, 1) == 0) {
3137 long prevStatusUpdateTime = r.mLastStatusBroadcast;
3138 if ((newStatusUpdateTime > prevStatusUpdateTime)
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003139 && (prevStatusUpdateTime != 0 || status != AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003140
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003141 r.mLastStatusBroadcast = newStatusUpdateTime;
3142 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
3143 receiverDead = true;
3144 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
3145 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07003146 }
3147 }
3148
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003149 // track expired records
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003150 if (r.mRealRequest.getNumUpdates() <= 0 || r.mRealRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003151 if (deadUpdateRecords == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003152 deadUpdateRecords = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003153 }
3154 deadUpdateRecords.add(r);
3155 }
3156 // track dead receivers
3157 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07003158 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003159 deadReceivers = new ArrayList<>();
Mike Lockwood03ca2162010-04-01 08:10:09 -07003160 }
3161 if (!deadReceivers.contains(receiver)) {
3162 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003163 }
3164 }
3165 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003166
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003167 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003168 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003169 for (Receiver receiver : deadReceivers) {
3170 removeUpdatesLocked(receiver);
3171 }
3172 }
3173 if (deadUpdateRecords != null) {
3174 for (UpdateRecord r : deadUpdateRecords) {
3175 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003176 }
Victoria Lease8b38b292012-12-04 15:04:43 -08003177 applyRequirementsLocked(provider);
3178 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003179 }
3180
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003181 /**
3182 * Updates last location with the given location
3183 *
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003184 * @param location new location to update
3185 * @param provider Location provider to update for
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003186 */
3187 private void updateLastLocationLocked(Location location, String provider) {
3188 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3189 Location lastNoGPSLocation;
3190 Location lastLocation = mLastLocation.get(provider);
3191 if (lastLocation == null) {
3192 lastLocation = new Location(provider);
3193 mLastLocation.put(provider, lastLocation);
3194 } else {
3195 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3196 if (noGPSLocation == null && lastNoGPSLocation != null) {
3197 // New location has no no-GPS location: adopt last no-GPS location. This is set
3198 // directly into location because we do not want to notify COARSE clients.
3199 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
3200 }
3201 }
3202 lastLocation.set(location);
3203 }
3204
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003205 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08003206 public LocationWorkerHandler(Looper looper) {
3207 super(looper, null, true);
3208 }
3209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003210 @Override
3211 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003212 switch (msg.what) {
3213 case MSG_LOCATION_CHANGED:
3214 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
3215 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003216 }
3217 }
3218 }
3219
Victoria Lease54ca7ae2013-01-08 09:39:50 -08003220 private boolean isMockProvider(String provider) {
3221 synchronized (mLock) {
3222 return mMockProviders.containsKey(provider);
3223 }
3224 }
3225
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003226 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08003227 // create a working copy of the incoming Location so that the service can modify it without
3228 // disturbing the caller's copy
3229 Location myLocation = new Location(location);
3230 String provider = myLocation.getProvider();
3231
3232 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
3233 // bit if location did not come from a mock provider because passive/fused providers can
3234 // forward locations from mock providers, and should not grant them legitimacy in doing so.
3235 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
3236 myLocation.setIsFromMockProvider(true);
3237 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08003238
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003239 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003240 if (!passive) {
3241 // notify passive provider of the new location
3242 mPassiveProvider.updateLocation(myLocation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003243 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003244 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003245 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003246 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003247
Mike Lockwoode97ae402010-09-29 15:23:46 -04003248 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
3249 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003250 public void onPackageDisappeared(String packageName, int reason) {
3251 // remove all receivers associated with this package name
3252 synchronized (mLock) {
3253 ArrayList<Receiver> deadReceivers = null;
3254
3255 for (Receiver receiver : mReceivers.values()) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003256 if (receiver.mIdentity.mPackageName.equals(packageName)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003257 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003258 deadReceivers = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003259 }
3260 deadReceivers.add(receiver);
3261 }
3262 }
3263
3264 // perform removal outside of mReceivers loop
3265 if (deadReceivers != null) {
3266 for (Receiver receiver : deadReceivers) {
3267 removeUpdatesLocked(receiver);
3268 }
3269 }
3270 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003271 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04003272 };
3273
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003274 // Geocoder
3275
Nick Pellye0fd6932012-07-11 10:26:13 -07003276 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04003277 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07003278 return mGeocodeProvider != null;
3279 }
3280
Nick Pellye0fd6932012-07-11 10:26:13 -07003281 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003282 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003283 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003284 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003285 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
3286 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003287 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003288 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003289 }
3290
Mike Lockwooda55c3212009-04-15 11:10:11 -04003291
Nick Pellye0fd6932012-07-11 10:26:13 -07003292 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003293 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04003294 double lowerLeftLatitude, double lowerLeftLongitude,
3295 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003296 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003297
3298 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003299 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
3300 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
3301 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003302 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003303 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003304 }
3305
3306 // Mock Providers
3307
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003308 private boolean canCallerAccessMockLocation(String opPackageName) {
3309 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
3310 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003311 }
3312
Nick Pellye0fd6932012-07-11 10:26:13 -07003313 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003314 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
3315 if (!canCallerAccessMockLocation(opPackageName)) {
3316 return;
3317 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003318
Mike Lockwooda4903f22010-02-17 06:42:23 -05003319 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
3320 throw new IllegalArgumentException("Cannot mock the passive location provider");
3321 }
3322
Mike Lockwood86328a92009-10-23 08:38:25 -04003323 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003324 synchronized (mLock) {
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003325 // remove the real provider if we are replacing GPS or network provider
3326 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07003327 || LocationManager.NETWORK_PROVIDER.equals(name)
3328 || LocationManager.FUSED_PROVIDER.equals(name)) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003329 LocationProvider p = mProvidersByName.get(name);
Mike Lockwoodd03ff942010-02-09 08:46:14 -05003330 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003331 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003332 }
3333 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003334 addTestProviderLocked(name, properties);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003335 }
Mike Lockwood86328a92009-10-23 08:38:25 -04003336 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003337 }
3338
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003339 private void addTestProviderLocked(String name, ProviderProperties properties) {
3340 if (mProvidersByName.get(name) != null) {
3341 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
3342 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003343
3344 LocationProvider provider = new LocationProvider(name);
3345 MockProvider mockProvider = new MockProvider(provider, properties);
3346
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003347 addProviderLocked(provider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003348 mMockProviders.put(name, mockProvider);
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003349 mLastLocation.put(name, null);
3350 mLastLocationCoarseInterval.put(name, null);
3351 }
3352
Nick Pellye0fd6932012-07-11 10:26:13 -07003353 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003354 public void removeTestProvider(String provider, String opPackageName) {
3355 if (!canCallerAccessMockLocation(opPackageName)) {
3356 return;
3357 }
3358
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003359 synchronized (mLock) {
You Kima6d0b6f2012-10-28 03:58:44 +09003360 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003361 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003362 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3363 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003364
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003365 long identity = Binder.clearCallingIdentity();
3366 try {
3367 removeProviderLocked(mProvidersByName.get(provider));
3368
3369 // reinstate real provider if available
3370 LocationProvider realProvider = mRealProviders.get(provider);
3371 if (realProvider != null) {
3372 addProviderLocked(realProvider);
3373 }
3374 mLastLocation.put(provider, null);
3375 mLastLocationCoarseInterval.put(provider, null);
3376 } finally {
3377 Binder.restoreCallingIdentity(identity);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003378 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003379 }
3380 }
3381
Nick Pellye0fd6932012-07-11 10:26:13 -07003382 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003383 public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
3384 if (!canCallerAccessMockLocation(opPackageName)) {
3385 return;
3386 }
3387
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003388 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003389 MockProvider mockProvider = mMockProviders.get(provider);
3390 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003391 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3392 }
Tom O'Neilla206a0f2016-12-15 10:26:28 -08003393
3394 // Ensure that the location is marked as being mock. There's some logic to do this in
3395 // handleLocationChanged(), but it fails if loc has the wrong provider (bug 33091107).
3396 Location mock = new Location(loc);
3397 mock.setIsFromMockProvider(true);
3398
3399 if (!TextUtils.isEmpty(loc.getProvider()) && !provider.equals(loc.getProvider())) {
3400 // The location has an explicit provider that is different from the mock provider
3401 // name. The caller may be trying to fool us via bug 33091107.
3402 EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
3403 provider + "!=" + loc.getProvider());
3404 }
3405
Mike Lockwood95427cd2009-05-07 13:27:54 -04003406 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
3407 long identity = Binder.clearCallingIdentity();
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003408 try {
3409 mockProvider.setLocation(mock);
3410 } finally {
3411 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003412 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003413 }
3414 }
3415
Nick Pellye0fd6932012-07-11 10:26:13 -07003416 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003417 public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
3418 if (!canCallerAccessMockLocation(opPackageName)) {
3419 return;
3420 }
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003421
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003422 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003423 MockProvider mockProvider = mMockProviders.get(provider);
3424 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003425 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3426 }
Mike Lockwood86328a92009-10-23 08:38:25 -04003427 long identity = Binder.clearCallingIdentity();
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003428 try {
3429 mockProvider.setEnabled(enabled);
3430 } finally {
3431 Binder.restoreCallingIdentity(identity);
3432 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003433 }
3434 }
3435
Nick Pellye0fd6932012-07-11 10:26:13 -07003436 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003437 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
3438 String opPackageName) {
3439 if (!canCallerAccessMockLocation(opPackageName)) {
3440 return;
3441 }
3442
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003443 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003444 MockProvider mockProvider = mMockProviders.get(provider);
3445 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003446 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3447 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003448 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003449 }
3450 }
3451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003452 private void log(String log) {
3453 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003454 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003455 }
3456 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003457
3458 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003459 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06003460 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Nick Pellye0fd6932012-07-11 10:26:13 -07003461
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003462 synchronized (mLock) {
Siddharth Raybb608c82017-03-16 11:33:34 -07003463 if (args.length > 0 && args[0].equals("--gnssmetrics")) {
3464 if (mGnssMetricsProvider != null) {
3465 pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
3466 }
3467 return;
3468 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003469 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003470 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003471 for (Receiver receiver : mReceivers.values()) {
3472 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003473 }
David Christie2ff96af2014-01-30 16:09:37 -08003474 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003475 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
3476 pw.println(" " + entry.getKey() + ":");
3477 for (UpdateRecord record : entry.getValue()) {
3478 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003479 }
3480 }
Wyatt Riley11cc7492018-01-17 08:48:27 -08003481 pw.println(" Active GnssMeasurement Listeners:");
3482 for (Identity identity : mGnssMeasurementsListeners.values()) {
3483 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3484 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3485 }
3486 pw.println(" Active GnssNavigationMessage Listeners:");
3487 for (Identity identity : mGnssNavigationMessageListeners.values()) {
3488 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3489 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3490 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003491 pw.println(" Overlay Provider Packages:");
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003492 for (LocationProvider provider : mProviders) {
3493 if (provider.mProvider instanceof LocationProviderProxy) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003494 pw.println(" " + provider.getName() + ": "
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003495 + ((LocationProviderProxy) provider.mProvider)
3496 .getConnectedPackageName());
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003497 }
3498 }
David Christie2ff96af2014-01-30 16:09:37 -08003499 pw.println(" Historical Records by Provider:");
3500 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
3501 : mRequestStatistics.statistics.entrySet()) {
3502 PackageProviderKey key = entry.getKey();
3503 PackageStatistics stats = entry.getValue();
3504 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
3505 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003506 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003507 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
3508 String provider = entry.getKey();
3509 Location location = entry.getValue();
3510 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003511 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003512
David Christie1b9b7b12013-04-15 15:31:11 -07003513 pw.println(" Last Known Locations Coarse Intervals:");
3514 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
3515 String provider = entry.getKey();
3516 Location location = entry.getValue();
3517 pw.println(" " + provider + ": " + location);
3518 }
3519
Nick Pellye0fd6932012-07-11 10:26:13 -07003520 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003521
Nick Pelly4035f5a2012-08-17 14:43:49 -07003522 pw.append(" ");
3523 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003524 if (mMockProviders.size() > 0) {
3525 pw.println(" Mock Providers:");
3526 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003527 i.getValue().dump(fd, pw, args);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003528 }
3529 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003530
Wei Wang980b7c22018-12-06 17:53:00 -08003531 if (mLocationControllerExtraPackage != null) {
3532 pw.println(" Location controller extra package: " + mLocationControllerExtraPackage
3533 + " enabled: " + mLocationControllerExtraPackageEnabled);
3534 }
3535
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08003536 if (!mBackgroundThrottlePackageWhitelist.isEmpty()) {
3537 pw.println(" Throttling Whitelisted Packages:");
3538 for (String packageName : mBackgroundThrottlePackageWhitelist) {
3539 pw.println(" " + packageName);
3540 }
3541 }
3542
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003543 pw.append(" fudger: ");
gomo48f1a642017-11-10 20:35:46 -08003544 mLocationFudger.dump(fd, pw, args);
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003545
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003546 if (args.length > 0 && "short".equals(args[0])) {
3547 return;
3548 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003549 for (LocationProvider provider : mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003550 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003551 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08003552 if (mGnssBatchingInProgress) {
3553 pw.println(" GNSS batching in progress");
3554 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003555 }
3556 }
3557}