blob: 9ebe896e668bc793a8b00e08aac9a4a7282da026 [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 Nagarkar90da1ab2019-01-04 16:26:59 -080020import static android.location.LocationManager.FUSED_PROVIDER;
21import static android.location.LocationManager.GPS_PROVIDER;
22import static android.location.LocationManager.NETWORK_PROVIDER;
23import static android.location.LocationManager.PASSIVE_PROVIDER;
Kweku Adams4fb074e2019-02-01 16:03:27 -080024import static android.os.PowerManager.locationPowerSaveModeToString;
Maggieaa080f92018-01-04 15:35:11 -080025
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -080026import static com.android.internal.util.Preconditions.checkNotNull;
Soonil Nagarkar1575a042018-10-24 17:54:54 -070027import static com.android.internal.util.Preconditions.checkState;
28
Wei Wang980b7c22018-12-06 17:53:00 -080029import android.Manifest;
Wyatt Rileycf879db2017-01-12 13:57:38 -080030import android.annotation.NonNull;
Wyatt Riley49097c02018-03-15 09:14:43 -070031import android.annotation.Nullable;
Maggieaa080f92018-01-04 15:35:11 -080032import android.app.ActivityManager;
33import android.app.AppOpsManager;
34import android.app.PendingIntent;
35import android.content.BroadcastReceiver;
Maggieaa080f92018-01-04 15:35:11 -080036import android.content.Context;
37import android.content.Intent;
38import android.content.IntentFilter;
39import android.content.pm.ApplicationInfo;
40import android.content.pm.PackageInfo;
41import android.content.pm.PackageManager;
42import android.content.pm.PackageManager.NameNotFoundException;
Maggieaa080f92018-01-04 15:35:11 -080043import android.content.pm.ResolveInfo;
44import android.content.pm.Signature;
45import android.content.res.Resources;
Brian Duddiecfa5b5b2019-01-22 18:01:40 +000046import android.hardware.location.ActivityRecognitionHardware;
Maggieaa080f92018-01-04 15:35:11 -080047import android.location.Address;
48import android.location.Criteria;
49import android.location.GeocoderParams;
50import android.location.Geofence;
gomo226b7b72018-12-12 16:49:39 -080051import android.location.GnssMeasurementCorrections;
Maggieaa080f92018-01-04 15:35:11 -080052import android.location.IBatchedLocationCallback;
53import android.location.IGnssMeasurementsListener;
54import android.location.IGnssNavigationMessageListener;
55import android.location.IGnssStatusListener;
Maggieaa080f92018-01-04 15:35:11 -080056import android.location.ILocationListener;
57import android.location.ILocationManager;
Maggieaa080f92018-01-04 15:35:11 -080058import android.location.Location;
59import android.location.LocationManager;
Maggieaa080f92018-01-04 15:35:11 -080060import android.location.LocationRequest;
Chad Brubakerf1133332019-03-15 14:13:59 -070061import android.location.LocationTime;
Maggieaa080f92018-01-04 15:35:11 -080062import android.os.Binder;
63import android.os.Bundle;
Soonil Nagarkar905e7222019-10-01 12:03:29 -070064import android.os.CancellationSignal;
Maggieaa080f92018-01-04 15:35:11 -080065import android.os.Handler;
66import android.os.IBinder;
Soonil Nagarkar905e7222019-10-01 12:03:29 -070067import android.os.ICancellationSignal;
Maggieaa080f92018-01-04 15:35:11 -080068import android.os.PowerManager;
Kweku Adams4fb074e2019-02-01 16:03:27 -080069import android.os.PowerManager.ServiceType;
70import android.os.PowerManagerInternal;
Maggieaa080f92018-01-04 15:35:11 -080071import android.os.Process;
72import android.os.RemoteException;
73import android.os.SystemClock;
74import android.os.UserHandle;
75import android.os.UserManager;
76import android.os.WorkSource;
Narayan Kamath32684dd2018-01-08 17:32:51 +000077import android.os.WorkSource.WorkChain;
Maggieaa080f92018-01-04 15:35:11 -080078import android.provider.Settings;
Hongyi Zhang700137e2019-05-23 21:19:36 -070079import android.stats.location.LocationStatsEnums;
Maggieaa080f92018-01-04 15:35:11 -080080import android.text.TextUtils;
Maggieaa080f92018-01-04 15:35:11 -080081import android.util.EventLog;
82import android.util.Log;
83import android.util.Slog;
WyattRileyba6072f2019-04-18 07:37:52 -070084import android.util.TimeUtils;
Yu-Han Yanga4d250e2018-10-02 21:29:20 -070085
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -080086import com.android.internal.annotations.GuardedBy;
destradaaea8a8a62014-06-23 18:19:03 -070087import com.android.internal.content.PackageMonitor;
88import com.android.internal.location.ProviderProperties;
89import com.android.internal.location.ProviderRequest;
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -070090import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060091import com.android.internal.util.DumpUtils;
Soonil Nagarkar1c572552019-07-10 13:31:47 -070092import com.android.internal.util.IndentingPrintWriter;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -080093import com.android.internal.util.Preconditions;
Soonil Nagarkar1575a042018-10-24 17:54:54 -070094import com.android.server.location.AbstractLocationProvider;
Brian Duddiecfa5b5b2019-01-22 18:01:40 +000095import com.android.server.location.ActivityRecognitionProxy;
Anil Admal08b96122019-01-30 16:55:05 -080096import com.android.server.location.CallerIdentity;
destradaaea8a8a62014-06-23 18:19:03 -070097import com.android.server.location.GeocoderProxy;
98import com.android.server.location.GeofenceManager;
99import com.android.server.location.GeofenceProxy;
destradaaea8a8a62014-06-23 18:19:03 -0700100import 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;
Soonil Nagarkarb8466b72019-10-25 14:10:30 -0700105import com.android.server.location.LocationSettingsStore;
destradaaea8a8a62014-06-23 18:19:03 -0700106import com.android.server.location.MockProvider;
107import com.android.server.location.PassiveProvider;
Todd Kennedy583378d2019-07-12 06:50:30 -0700108import com.android.server.pm.permission.PermissionManagerServiceInternal;
Yu-Han Yanga4d250e2018-10-02 21:29:20 -0700109
Soonil Nagarkarae6ce772019-05-01 13:16:17 -0700110import java.io.ByteArrayOutputStream;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400111import java.io.FileDescriptor;
Soonil Nagarkarae6ce772019-05-01 13:16:17 -0700112import java.io.PrintStream;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400113import java.io.PrintWriter;
114import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700115import java.util.Arrays;
Soonil Nagarkar0d77ea62019-01-31 14:36:56 -0800116import java.util.Collections;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400117import java.util.HashMap;
118import java.util.HashSet;
119import java.util.List;
120import java.util.Map;
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800121import java.util.Map.Entry;
Soonil Nagarkar905e7222019-10-01 12:03:29 -0700122import java.util.concurrent.TimeUnit;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123
124/**
125 * The service class that manages LocationProviders and issues location
126 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 */
Victoria Lease5cd731a2012-12-19 15:04:21 -0800128public class LocationManagerService extends ILocationManager.Stub {
Soonil Nagarkar141417a2019-10-28 11:12:48 -0700129
130 /**
131 * Controls lifecycle of LocationManagerService.
132 */
133 public static class Lifecycle extends SystemService {
134
135 private LocationManagerService mService;
136
137 public Lifecycle(Context context) {
138 super(context);
139 mService = new LocationManagerService(context);
140 }
141
142 @Override
143 public void onStart() {
144 publishBinderService(Context.LOCATION_SERVICE, mService);
145 }
146
147 @Override
148 public void onBootPhase(int phase) {
149 if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
150 mService.systemRunning();
151 }
152 }
153 }
154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -0800156 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700157
Olivier Gaillard7a222662017-11-20 16:07:24 +0000158 private static final String WAKELOCK_KEY = "*location*";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159
Victoria Lease37425c32012-10-16 16:08:48 -0700160 // Location resolution level: no location data whatsoever
161 private static final int RESOLUTION_LEVEL_NONE = 0;
162 // Location resolution level: coarse location data only
163 private static final int RESOLUTION_LEVEL_COARSE = 1;
164 // Location resolution level: fine location data
165 private static final int RESOLUTION_LEVEL_FINE = 2;
166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700168 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169
170 private static final String NETWORK_LOCATION_SERVICE_ACTION =
Stan Chesnutt39062dd2013-07-22 14:33:30 -0700171 "com.android.location.service.v3.NetworkLocationProvider";
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700172 private static final String FUSED_LOCATION_SERVICE_ACTION =
173 "com.android.location.service.FusedLocationProvider";
174
David Christie0b837452013-07-29 16:02:13 -0700175 // The maximum interval a location request can have and still be considered "high power".
176 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
177
Soonil Nagarkar905e7222019-10-01 12:03:29 -0700178 // maximum age of a location before it is no longer considered "current"
179 private static final long MAX_CURRENT_LOCATION_AGE_MS = 10 * 1000;
180
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700181 private static final int FOREGROUND_IMPORTANCE_CUTOFF
gomo48f1a642017-11-10 20:35:46 -0800182 = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700183
Nick Pellyf1be6862012-05-15 10:53:42 -0700184 // Location Providers may sometimes deliver location updates
185 // slightly faster that requested - provide grace period so
186 // we don't unnecessarily filter events that are otherwise on
187 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700188 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700189
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700190 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
191
Soonil Nagarkar68257742019-01-09 19:42:34 +0000192 private final Object mLock = new Object();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800193 private final Context mContext;
194 private final Handler mHandler;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700195
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800196 private AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700197 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700198 private PowerManager mPowerManager;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800199 private ActivityManager mActivityManager;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700200 private UserManager mUserManager;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800201
Soonil Nagarkarb8466b72019-10-25 14:10:30 -0700202 private LocationSettingsStore mSettingsStore;
203
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800204 private GeofenceManager mGeofenceManager;
205 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700206 private GeocoderProxy mGeocodeProvider;
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700207 @Nullable
208 private GnssManagerService mGnssManagerService;
209 private PassiveProvider mPassiveProvider; // track passive provider for special cases
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800210 @GuardedBy("mLock")
Wei Wang114922a2019-01-30 18:19:35 -0800211 private String mExtraLocationControllerPackage;
212 private boolean mExtraLocationControllerPackageEnabled;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700213
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800214 // list of currently active providers
215 @GuardedBy("mLock")
216 private final ArrayList<LocationProvider> mProviders = new ArrayList<>();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000217
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800218 // list of non-mock providers, so that when mock providers replace real providers, they can be
219 // later re-replaced
220 @GuardedBy("mLock")
221 private final ArrayList<LocationProvider> mRealProviders = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800223 @GuardedBy("mLock")
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800224 private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700225 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800226 new HashMap<>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700227
David Christie2ff96af2014-01-30 16:09:37 -0800228 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
229
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700230 // mapping from provider name to last known location
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800231 @GuardedBy("mLock")
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800232 private final HashMap<String, Location> mLastLocation = new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233
David Christie1b9b7b12013-04-15 15:31:11 -0700234 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
235 // locations stored here are not fudged for coarse permissions.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800236 @GuardedBy("mLock")
David Christie1b9b7b12013-04-15 15:31:11 -0700237 private final HashMap<String, Location> mLastLocationCoarseInterval =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800238 new HashMap<>();
David Christie1b9b7b12013-04-15 15:31:11 -0700239
Victoria Lease38389b62012-09-30 11:44:22 -0700240 // current active user on the device - other users are denied location data
Xiaohui Chena4490622015-09-22 15:29:31 -0700241 private int mCurrentUserId = UserHandle.USER_SYSTEM;
gomo48f1a642017-11-10 20:35:46 -0800242 private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
Victoria Lease38389b62012-09-30 11:44:22 -0700243
Kweku Adams4fb074e2019-02-01 16:03:27 -0800244 @GuardedBy("mLock")
245 @PowerManager.LocationPowerSaveMode
246 private int mBatterySaverMode;
247
Hongyi Zhang700137e2019-05-23 21:19:36 -0700248 @GuardedBy("mLock")
249 private final LocationUsageLogger mLocationUsageLogger;
250
Soonil Nagarkar141417a2019-10-28 11:12:48 -0700251 private LocationManagerService(Context context) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700252 mContext = context;
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -0800253 mHandler = FgThread.getHandler();
Hongyi Zhang700137e2019-05-23 21:19:36 -0700254 mLocationUsageLogger = new LocationUsageLogger();
The Android Open Source Project4df24232009-03-05 14:34:35 -0800255
Svet Ganovadc1cf42015-06-15 16:36:24 -0700256 // Let the package manager query which are the default location
257 // providers as they get certain permissions granted by default.
Todd Kennedy583378d2019-07-12 06:50:30 -0700258 PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService(
259 PermissionManagerServiceInternal.class);
260 permissionManagerInternal.setLocationPackagesProvider(
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700261 userId -> mContext.getResources().getStringArray(
262 com.android.internal.R.array.config_locationProviderPackageNames));
Todd Kennedy583378d2019-07-12 06:50:30 -0700263 permissionManagerInternal.setLocationExtraPackagesProvider(
Wei Wangffb94e62019-01-14 00:05:45 -0800264 userId -> mContext.getResources().getStringArray(
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700265 com.android.internal.R.array.config_locationExtraPackageNames));
Svet Ganovadc1cf42015-06-15 16:36:24 -0700266
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700267 // most startup is deferred until systemRunning()
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700268 }
269
Soonil Nagarkar141417a2019-10-28 11:12:48 -0700270 private void systemRunning() {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000271 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800272 initializeLocked();
Victoria Lease5cd731a2012-12-19 15:04:21 -0800273 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800274 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700275
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800276 @GuardedBy("mLock")
277 private void initializeLocked() {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800278 mPackageManager = mContext.getPackageManager();
Soonil Nagarkarb8466b72019-10-25 14:10:30 -0700279 mAppOps = mContext.getSystemService(AppOpsManager.class);
280 mPowerManager = mContext.getSystemService(PowerManager.class);
281 mActivityManager = mContext.getSystemService(ActivityManager.class);
282 mUserManager = mContext.getSystemService(UserManager.class);
283
284 mSettingsStore = new LocationSettingsStore(mContext, mHandler);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800285
286 mLocationFudger = new LocationFudger(mContext, mHandler);
Soonil Nagarkarb8466b72019-10-25 14:10:30 -0700287 mGeofenceManager = new GeofenceManager(mContext, mSettingsStore);
288
289 PowerManagerInternal localPowerManager =
290 LocalServices.getService(PowerManagerInternal.class);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800291
292 // prepare providers
293 initializeProvidersLocked();
294
295 // add listeners
296 mAppOps.startWatchingMode(
297 AppOpsManager.OP_COARSE_LOCATION,
298 null,
299 AppOpsManager.WATCH_FOREGROUND_CHANGES,
300 new AppOpsManager.OnOpChangedInternalListener() {
301 public void onOpChanged(int op, String packageName) {
Soonil Nagarkarea8801a2019-03-19 11:11:56 -0700302 // onOpChanged invoked on ui thread, move to our thread to reduce risk of
303 // blocking ui thread
304 mHandler.post(() -> {
305 synchronized (mLock) {
306 onAppOpChangedLocked();
307 }
308 });
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800309 }
310 });
311 mPackageManager.addOnPermissionsChangeListener(
312 uid -> {
Soonil Nagarkare770ea62019-03-26 21:17:10 -0700313 // listener invoked on ui thread, move to our thread to reduce risk of blocking
314 // ui thread
315 mHandler.post(() -> {
316 synchronized (mLock) {
317 onPermissionsChangedLocked();
318 }
319 });
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800320 });
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800321 mActivityManager.addOnUidImportanceListener(
322 (uid, importance) -> {
Soonil Nagarkare770ea62019-03-26 21:17:10 -0700323 // listener invoked on ui thread, move to our thread to reduce risk of blocking
324 // ui thread
325 mHandler.post(() -> {
326 synchronized (mLock) {
327 onUidImportanceChangedLocked(uid, importance);
328 }
329 });
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800330 },
331 FOREGROUND_IMPORTANCE_CUTOFF);
Soonil Nagarkarb8466b72019-10-25 14:10:30 -0700332
Kweku Adams4fb074e2019-02-01 16:03:27 -0800333 localPowerManager.registerLowPowerModeObserver(ServiceType.LOCATION,
334 state -> {
Soonil Nagarkare770ea62019-03-26 21:17:10 -0700335 // listener invoked on ui thread, move to our thread to reduce risk of blocking
336 // ui thread
337 mHandler.post(() -> {
338 synchronized (mLock) {
339 onBatterySaverModeChangedLocked(state.locationMode);
340 }
341 });
Kweku Adams4fb074e2019-02-01 16:03:27 -0800342 });
Soonil Nagarkarb8466b72019-10-25 14:10:30 -0700343 mBatterySaverMode = mPowerManager.getLocationPowerSaveMode();
344
345 mSettingsStore.addOnLocationEnabledChangedListener(() -> {
346 synchronized (mLock) {
347 onLocationModeChangedLocked(true);
348 }
349 });
350 mSettingsStore.addOnLocationProvidersAllowedChangedListener(() -> {
351 synchronized (mLock) {
352 onProviderAllowedChangedLocked();
353 }
354 });
355 mSettingsStore.addOnBackgroundThrottleIntervalChangedListener(() -> {
356 synchronized (mLock) {
357 onBackgroundThrottleIntervalChangedLocked();
358 }
359 });
360 mSettingsStore.addOnBackgroundThrottlePackageWhitelistChangedListener(() -> {
361 synchronized (mLock) {
362 onBackgroundThrottleWhitelistChangedLocked();
363 }
364 });
365 mSettingsStore.addOnIgnoreSettingsPackageWhitelistChangedListener(() -> {
366 synchronized (mLock) {
367 onIgnoreSettingsWhitelistChangedLocked();
368 }
369 });
Wei Wangdd070f22018-06-21 11:29:40 -0700370
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800371 new PackageMonitor() {
372 @Override
373 public void onPackageDisappeared(String packageName, int reason) {
374 synchronized (mLock) {
375 LocationManagerService.this.onPackageDisappearedLocked(packageName);
376 }
377 }
378 }.register(mContext, mHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700379
Victoria Lease38389b62012-09-30 11:44:22 -0700380 IntentFilter intentFilter = new IntentFilter();
381 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700382 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
383 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
Kweku Adams4fb074e2019-02-01 16:03:27 -0800384 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
385 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
Victoria Lease38389b62012-09-30 11:44:22 -0700386
387 mContext.registerReceiverAsUser(new BroadcastReceiver() {
388 @Override
389 public void onReceive(Context context, Intent intent) {
Kweku Adams4fb074e2019-02-01 16:03:27 -0800390 final String action = intent.getAction();
391 if (action == null) {
392 return;
393 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800394 synchronized (mLock) {
Kweku Adams4fb074e2019-02-01 16:03:27 -0800395 switch (action) {
396 case Intent.ACTION_USER_SWITCHED:
397 onUserChangedLocked(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
398 break;
399 case Intent.ACTION_MANAGED_PROFILE_ADDED:
400 case Intent.ACTION_MANAGED_PROFILE_REMOVED:
401 onUserProfilesChangedLocked();
402 break;
403 case Intent.ACTION_SCREEN_ON:
404 case Intent.ACTION_SCREEN_OFF:
405 onScreenStateChangedLocked();
406 break;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800407 }
Victoria Lease38389b62012-09-30 11:44:22 -0700408 }
409 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800410 }, UserHandle.ALL, intentFilter, null, mHandler);
411
412 // switching the user from null to system here performs the bulk of the initialization work.
413 // the user being changed will cause a reload of all user specific settings, which causes
414 // provider initialization, and propagates changes until a steady state is reached
415 mCurrentUserId = UserHandle.USER_NULL;
Soonil Nagarkardb49bea2019-07-12 09:56:26 -0700416 onUserChangedLocked(ActivityManager.getCurrentUser());
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700417 }
418
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800419 @GuardedBy("mLock")
420 private void onAppOpChangedLocked() {
421 for (Receiver receiver : mReceivers.values()) {
422 receiver.updateMonitoring(true);
423 }
424 for (LocationProvider p : mProviders) {
425 applyRequirementsLocked(p);
426 }
427 }
428
429 @GuardedBy("mLock")
430 private void onPermissionsChangedLocked() {
431 for (LocationProvider p : mProviders) {
432 applyRequirementsLocked(p);
433 }
434 }
435
436 @GuardedBy("mLock")
Kweku Adams4fb074e2019-02-01 16:03:27 -0800437 private void onBatterySaverModeChangedLocked(int newLocationMode) {
Soonil Nagarkarb8466b72019-10-25 14:10:30 -0700438 if (mBatterySaverMode == newLocationMode) {
439 return;
440 }
441
Kweku Adams4fb074e2019-02-01 16:03:27 -0800442 if (D) {
443 Slog.d(TAG,
444 "Battery Saver location mode changed from "
445 + locationPowerSaveModeToString(mBatterySaverMode) + " to "
446 + locationPowerSaveModeToString(newLocationMode));
447 }
448
Kweku Adams4fb074e2019-02-01 16:03:27 -0800449 mBatterySaverMode = newLocationMode;
Soonil Nagarkarb8466b72019-10-25 14:10:30 -0700450
Kweku Adams4fb074e2019-02-01 16:03:27 -0800451 for (LocationProvider p : mProviders) {
452 applyRequirementsLocked(p);
453 }
454 }
455
456 @GuardedBy("mLock")
457 private void onScreenStateChangedLocked() {
458 if (mBatterySaverMode == PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF) {
459 for (LocationProvider p : mProviders) {
460 applyRequirementsLocked(p);
461 }
462 }
463 }
464
465 @GuardedBy("mLock")
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800466 private void onLocationModeChangedLocked(boolean broadcast) {
Soonil Nagarkar4ee3ac22019-02-08 19:19:24 -0800467 if (D) {
468 Log.d(TAG, "location enabled is now " + isLocationEnabled());
469 }
470
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800471 for (LocationProvider p : mProviders) {
472 p.onLocationModeChangedLocked();
473 }
474
475 if (broadcast) {
Soonil Nagarkar3126c902019-03-04 18:29:49 -0800476 // needs to be sent to everyone because we don't know which user may have changed
477 // LOCATION_MODE state.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800478 mContext.sendBroadcastAsUser(
479 new Intent(LocationManager.MODE_CHANGED_ACTION),
480 UserHandle.ALL);
481 }
482 }
483
484 @GuardedBy("mLock")
Soonil Nagarkar4ee3ac22019-02-08 19:19:24 -0800485 private void onProviderAllowedChangedLocked() {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800486 for (LocationProvider p : mProviders) {
487 p.onAllowedChangedLocked();
488 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800489 }
490
491 @GuardedBy("mLock")
492 private void onPackageDisappearedLocked(String packageName) {
493 ArrayList<Receiver> deadReceivers = null;
494
495 for (Receiver receiver : mReceivers.values()) {
Anil Admal08b96122019-01-30 16:55:05 -0800496 if (receiver.mCallerIdentity.mPackageName.equals(packageName)) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800497 if (deadReceivers == null) {
498 deadReceivers = new ArrayList<>();
499 }
500 deadReceivers.add(receiver);
501 }
502 }
503
504 // perform removal outside of mReceivers loop
505 if (deadReceivers != null) {
506 for (Receiver receiver : deadReceivers) {
507 removeUpdatesLocked(receiver);
508 }
509 }
510 }
511
512 @GuardedBy("mLock")
513 private void onUidImportanceChangedLocked(int uid, int importance) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700514 boolean foreground = LocationManagerServiceUtils.isImportanceForeground(importance);
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700515 HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800516 for (Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
517 String provider = entry.getKey();
518 for (UpdateRecord record : entry.getValue()) {
Anil Admal08b96122019-01-30 16:55:05 -0800519 if (record.mReceiver.mCallerIdentity.mUid == uid
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800520 && record.mIsForegroundUid != foreground) {
gomo48f1a642017-11-10 20:35:46 -0800521 if (D) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800522 Log.d(TAG, "request from uid " + uid + " is now "
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700523 + LocationManagerServiceUtils.foregroundAsString(
524 foreground));
gomo48f1a642017-11-10 20:35:46 -0800525 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800526 record.updateForeground(foreground);
527
Anil Admal08b96122019-01-30 16:55:05 -0800528 if (!isThrottlingExemptLocked(record.mReceiver.mCallerIdentity)) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800529 affectedProviders.add(provider);
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700530 }
531 }
532 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800533 }
534 for (String provider : affectedProviders) {
535 applyRequirementsLocked(provider);
536 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800537 }
538
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800539 @GuardedBy("mLock")
540 private void onBackgroundThrottleIntervalChangedLocked() {
541 for (LocationProvider provider : mProviders) {
542 applyRequirementsLocked(provider);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000543 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800544 }
545
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800546 @GuardedBy("mLock")
547 private void onBackgroundThrottleWhitelistChangedLocked() {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800548 for (LocationProvider p : mProviders) {
549 applyRequirementsLocked(p);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000550 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800551 }
552
Soonil Nagarkar397ad582019-01-23 22:47:57 -0800553 @GuardedBy("lock")
554 private void onIgnoreSettingsWhitelistChangedLocked() {
Soonil Nagarkar397ad582019-01-23 22:47:57 -0800555 for (LocationProvider p : mProviders) {
556 applyRequirementsLocked(p);
557 }
558 }
559
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800560 @GuardedBy("mLock")
561 private void onUserProfilesChangedLocked() {
562 mCurrentUserProfiles = mUserManager.getProfileIdsWithDisabled(mCurrentUserId);
563 }
564
565 @GuardedBy("mLock")
566 private boolean isCurrentProfileLocked(int userId) {
567 return ArrayUtils.contains(mCurrentUserProfiles, userId);
568 }
569
570 @GuardedBy("mLock")
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700571 private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) {
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500572 PackageManager pm = mContext.getPackageManager();
573 String systemPackageName = mContext.getPackageName();
574 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
575
576 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
577 new Intent(FUSED_LOCATION_SERVICE_ACTION),
578 PackageManager.GET_META_DATA, mCurrentUserId);
579 for (ResolveInfo rInfo : rInfos) {
580 String packageName = rInfo.serviceInfo.packageName;
581
582 // Check that the signature is in the list of supported sigs. If it's not in
583 // this list the standard provider binding logic won't bind to it.
584 try {
585 PackageInfo pInfo;
586 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
587 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
588 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
589 ", but has wrong signature, ignoring");
590 continue;
591 }
592 } catch (NameNotFoundException e) {
593 Log.e(TAG, "missing package: " + packageName);
594 continue;
595 }
596
597 // Get the version info
598 if (rInfo.serviceInfo.metaData == null) {
599 Log.w(TAG, "Found fused provider without metadata: " + packageName);
600 continue;
601 }
602
603 int version = rInfo.serviceInfo.metaData.getInt(
604 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
605 if (version == 0) {
606 // This should be the fallback fused location provider.
607
608 // Make sure it's in the system partition.
609 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
610 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
611 continue;
612 }
613
614 // Check that the fallback is signed the same as the OS
615 // as a proxy for coreApp="true"
616 if (pm.checkSignatures(systemPackageName, packageName)
617 != PackageManager.SIGNATURE_MATCH) {
gomo48f1a642017-11-10 20:35:46 -0800618 if (D) {
619 Log.d(TAG, "Fallback candidate not signed the same as system: "
620 + packageName);
621 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500622 continue;
623 }
624
625 // Found a valid fallback.
626 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
627 return;
628 } else {
629 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
630 }
631 }
632
633 throw new IllegalStateException("Unable to find a fused location provider that is in the "
634 + "system partition with version 0 and signed with the platform certificate. "
635 + "Such a package is needed to provide a default fused location provider in the "
636 + "event that no other fused location provider has been installed or is currently "
637 + "available. For example, coreOnly boot mode when decrypting the data "
638 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
639 }
640
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800641 @GuardedBy("mLock")
642 private void initializeProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700643 // create a passive location provider, which is always enabled
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800644 LocationProvider passiveProviderManager = new LocationProvider(PASSIVE_PROVIDER);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000645 addProviderLocked(passiveProviderManager);
Soonil Nagarkar0d77ea62019-01-31 14:36:56 -0800646 mPassiveProvider = new PassiveProvider(mContext, passiveProviderManager);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800647 passiveProviderManager.attachLocked(mPassiveProvider);
Victoria Lease5c24fd02012-10-01 11:00:50 -0700648
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700649 if (GnssManagerService.isGnssSupported()) {
650 // Create a gps location provider manager
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800651 LocationProvider gnssProviderManager = new LocationProvider(GPS_PROVIDER, true);
652 mRealProviders.add(gnssProviderManager);
653 addProviderLocked(gnssProviderManager);
654
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700655 mGnssManagerService = new GnssManagerService(this, mContext, gnssProviderManager,
656 mLocationUsageLogger);
657 gnssProviderManager.attachLocked(mGnssManagerService.getGnssLocationProvider());
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700658 }
659
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700660 /*
661 Load package name(s) containing location provider support.
662 These packages can contain services implementing location providers:
663 Geocoder Provider, Network Location Provider, and
664 Fused Location Provider. They will each be searched for
665 service components implementing these providers.
666 The location framework also has support for installation
667 of new location providers at run-time. The new package does not
668 have to be explicitly listed here, however it must have a signature
669 that matches the signature of at least one package on this list.
670 */
671 Resources resources = mContext.getResources();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500672 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700673 com.android.internal.R.array.config_locationProviderPackageNames);
gomo48f1a642017-11-10 20:35:46 -0800674 if (D) {
675 Log.d(TAG, "certificates for location providers pulled from: " +
676 Arrays.toString(pkgs));
677 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500678
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700679 ensureFallbackFusedProviderPresentLocked(pkgs);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700680
681 // bind to network provider
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800682 LocationProvider networkProviderManager = new LocationProvider(NETWORK_PROVIDER, true);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700683 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
684 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700685 networkProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700686 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700687 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
688 com.android.internal.R.string.config_networkLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700689 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700690 if (networkProvider != null) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800691 mRealProviders.add(networkProviderManager);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000692 addProviderLocked(networkProviderManager);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800693 networkProviderManager.attachLocked(networkProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700694 } else {
gomo48f1a642017-11-10 20:35:46 -0800695 Slog.w(TAG, "no network location provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700696 }
697
698 // bind to fused provider
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800699 LocationProvider fusedProviderManager = new LocationProvider(FUSED_PROVIDER);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700700 LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700701 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700702 fusedProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700703 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700704 com.android.internal.R.bool.config_enableFusedLocationOverlay,
705 com.android.internal.R.string.config_fusedLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700706 com.android.internal.R.array.config_locationProviderPackageNames);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700707 if (fusedProvider != null) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800708 mRealProviders.add(fusedProviderManager);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000709 addProviderLocked(fusedProviderManager);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800710 fusedProviderManager.attachLocked(fusedProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700711 } else {
712 Slog.e(TAG, "no fused location provider found",
713 new IllegalStateException("Location service needs a fused location provider"));
714 }
715
716 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700717 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
718 com.android.internal.R.bool.config_enableGeocoderOverlay,
719 com.android.internal.R.string.config_geocoderProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700720 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700721 if (mGeocodeProvider == null) {
gomo48f1a642017-11-10 20:35:46 -0800722 Slog.e(TAG, "no geocoder provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700723 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700724
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700725 if (mGnssManagerService != null) {
726 // bind to geofence provider
727 GeofenceProxy provider = GeofenceProxy.createAndBind(
728 mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
729 com.android.internal.R.string.config_geofenceProviderPackageName,
730 com.android.internal.R.array.config_locationProviderPackageNames,
731 mGnssManagerService.getGpsGeofenceProxy(),
732 null);
733 if (provider == null) {
734 Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
735 }
destradaa0682809a2013-08-12 18:50:30 -0700736 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900737
Brian Duddiecfa5b5b2019-01-22 18:01:40 +0000738 // bind to hardware activity recognition
739 boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported();
740 ActivityRecognitionHardware activityRecognitionHardware = null;
741 if (activityRecognitionHardwareIsSupported) {
742 activityRecognitionHardware = ActivityRecognitionHardware.getInstance(mContext);
743 } else {
744 Slog.d(TAG, "Hardware Activity-Recognition not supported.");
745 }
746 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
747 mContext,
748 activityRecognitionHardwareIsSupported,
749 activityRecognitionHardware,
750 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
751 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
752 com.android.internal.R.array.config_locationProviderPackageNames);
753 if (proxy == null) {
754 Slog.d(TAG, "Unable to bind ActivityRecognitionProxy.");
755 }
756
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900757 String[] testProviderStrings = resources.getStringArray(
758 com.android.internal.R.array.config_testLocationProviders);
759 for (String testProviderString : testProviderStrings) {
Soonil Nagarkarb46c1672019-02-06 12:49:10 -0800760 String[] fragments = testProviderString.split(",");
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900761 String name = fragments[0].trim();
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900762 ProviderProperties properties = new ProviderProperties(
763 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
764 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
765 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
766 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
767 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
768 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
769 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
770 Integer.parseInt(fragments[8]) /* powerRequirement */,
771 Integer.parseInt(fragments[9]) /* accuracy */);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800772 LocationProvider testProviderManager = new LocationProvider(name);
773 addProviderLocked(testProviderManager);
Soonil Nagarkard334f7b2019-07-08 16:16:19 -0700774 testProviderManager.attachLocked(
775 new MockProvider(mContext, testProviderManager, properties));
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900776 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700777 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700778
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800779 @GuardedBy("mLock")
780 private void onUserChangedLocked(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800781 if (mCurrentUserId == userId) {
782 return;
783 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800784
Soonil Nagarkar4ee3ac22019-02-08 19:19:24 -0800785 if (D) {
786 Log.d(TAG, "foreground user is changing to " + userId);
787 }
788
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800789 // let providers know the current user is on the way out before changing the user
790 for (LocationProvider p : mProviders) {
791 p.onUserChangingLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000792 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800793
794 mCurrentUserId = userId;
795 onUserProfilesChangedLocked();
796
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800797 // if the user changes, per-user settings may also have changed
798 onLocationModeChangedLocked(false);
Soonil Nagarkar4ee3ac22019-02-08 19:19:24 -0800799 onProviderAllowedChangedLocked();
800
801 // always force useability to be rechecked, even if no per-user settings have changed
802 for (LocationProvider p : mProviders) {
803 p.onUseableChangedLocked(false);
804 }
Victoria Lease38389b62012-09-30 11:44:22 -0700805 }
806
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700807 /**
808 * Location provider manager, manages a LocationProvider.
809 */
810 class LocationProvider implements AbstractLocationProvider.LocationProviderManager {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700811
812 private final String mName;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700813
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800814 // whether this provider should respect LOCATION_PROVIDERS_ALLOWED (ie gps and network)
815 private final boolean mIsManagedBySettings;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700816
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800817 // remember to clear binder identity before invoking any provider operation
818 @GuardedBy("mLock")
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700819 @Nullable
820 protected AbstractLocationProvider mProvider;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700821
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800822 @GuardedBy("mLock")
823 private boolean mUseable; // combined state
824 @GuardedBy("mLock")
825 private boolean mAllowed; // state of LOCATION_PROVIDERS_ALLOWED
826 @GuardedBy("mLock")
827 private boolean mEnabled; // state of provider
828
829 @GuardedBy("mLock")
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700830 @Nullable
831 private ProviderProperties mProperties;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700832
833 private LocationProvider(String name) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800834 this(name, false);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700835 }
836
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800837 private LocationProvider(String name, boolean isManagedBySettings) {
838 mName = name;
839 mIsManagedBySettings = isManagedBySettings;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700840
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800841 mProvider = null;
842 mUseable = false;
843 mAllowed = !mIsManagedBySettings;
844 mEnabled = false;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700845 mProperties = null;
Soonil Nagarkar42da1b12019-01-22 11:29:27 -0800846
847 if (mIsManagedBySettings) {
848 // since we assume providers are disabled by default
849 Settings.Secure.putStringForUser(
850 mContext.getContentResolver(),
851 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
852 "-" + mName,
853 mCurrentUserId);
854 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700855 }
856
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800857 @GuardedBy("mLock")
858 public void attachLocked(AbstractLocationProvider provider) {
859 checkNotNull(provider);
860 checkState(mProvider == null);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800861
Soonil Nagarkar4ee3ac22019-02-08 19:19:24 -0800862 if (D) {
863 Log.d(TAG, mName + " provider attached");
864 }
865
866 mProvider = provider;
867 onUseableChangedLocked(false);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800868 }
869
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700870 public String getName() {
871 return mName;
872 }
873
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800874 @GuardedBy("mLock")
Soonil Nagarkar0d77ea62019-01-31 14:36:56 -0800875 public List<String> getPackagesLocked() {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800876 if (mProvider == null) {
Soonil Nagarkar0d77ea62019-01-31 14:36:56 -0800877 return Collections.emptyList();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800878 } else {
Soonil Nagarkar0d77ea62019-01-31 14:36:56 -0800879 // safe to not clear binder context since this doesn't call into the real provider
880 return mProvider.getProviderPackages();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800881 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700882 }
883
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800884 public boolean isMock() {
885 return false;
886 }
887
888 @GuardedBy("mLock")
889 public boolean isPassiveLocked() {
890 return mProvider == mPassiveProvider;
891 }
892
893 @GuardedBy("mLock")
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700894 @Nullable
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800895 public ProviderProperties getPropertiesLocked() {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700896 return mProperties;
897 }
898
Soonil Nagarkard334f7b2019-07-08 16:16:19 -0700899 public void setRequest(ProviderRequest request, WorkSource workSource) {
900 // move calls going to providers onto a different thread to avoid deadlock
901 mHandler.post(() -> {
902 synchronized (mLock) {
903 if (mProvider != null) {
904 mProvider.onSetRequest(request, workSource);
905 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800906 }
Soonil Nagarkard334f7b2019-07-08 16:16:19 -0700907 });
908 }
909
910 public void sendExtraCommand(String command, Bundle extras) {
911 int uid = Binder.getCallingUid();
912 int pid = Binder.getCallingPid();
913
914 // move calls going to providers onto a different thread to avoid deadlock
915 mHandler.post(() -> {
916 synchronized (mLock) {
917 if (mProvider != null) {
918 mProvider.onSendExtraCommand(uid, pid, command, extras);
919 }
920 }
921 });
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700922 }
923
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800924 @GuardedBy("mLock")
Soonil Nagarkar1c572552019-07-10 13:31:47 -0700925 public void dumpLocked(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
926 pw.print(mName + " provider");
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800927 if (isMock()) {
Soonil Nagarkarb46c1672019-02-06 12:49:10 -0800928 pw.print(" [mock]");
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800929 }
Soonil Nagarkarb46c1672019-02-06 12:49:10 -0800930 pw.println(":");
931
Soonil Nagarkar1c572552019-07-10 13:31:47 -0700932 pw.increaseIndent();
933
934 pw.println("useable=" + mUseable);
Soonil Nagarkarb46c1672019-02-06 12:49:10 -0800935 if (!mUseable) {
Soonil Nagarkar1c572552019-07-10 13:31:47 -0700936 pw.println("attached=" + (mProvider != null));
Soonil Nagarkarb46c1672019-02-06 12:49:10 -0800937 if (mIsManagedBySettings) {
Soonil Nagarkar1c572552019-07-10 13:31:47 -0700938 pw.println("allowed=" + mAllowed);
Soonil Nagarkarb46c1672019-02-06 12:49:10 -0800939 }
Soonil Nagarkar1c572552019-07-10 13:31:47 -0700940 pw.println("enabled=" + mEnabled);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800941 }
Soonil Nagarkarb46c1672019-02-06 12:49:10 -0800942
Soonil Nagarkar1c572552019-07-10 13:31:47 -0700943 pw.println("properties=" + mProperties);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800944
945 if (mProvider != null) {
Soonil Nagarkar1c572552019-07-10 13:31:47 -0700946 // in order to be consistent with other provider APIs, this should be run on the
947 // location thread... but this likely isn't worth it just for dumping info.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800948 long identity = Binder.clearCallingIdentity();
949 try {
950 mProvider.dump(fd, pw, args);
951 } finally {
952 Binder.restoreCallingIdentity(identity);
953 }
954 }
Soonil Nagarkar1c572552019-07-10 13:31:47 -0700955
956 pw.decreaseIndent();
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700957 }
958
Soonil Nagarkard334f7b2019-07-08 16:16:19 -0700959 @Override
960 public void onReportLocation(Location location) {
Soonil Nagarkar7fc24c62019-10-18 17:32:38 -0700961 // likelihood of a 0,0 bug is far greater than this being a valid location
962 if (!isMock() && location.getLatitude() == 0 && location.getLongitude() == 0) {
963 Slog.w(TAG, "blocking 0,0 location from " + mName + " provider");
964 return;
965 }
966
Soonil Nagarkard334f7b2019-07-08 16:16:19 -0700967 synchronized (mLock) {
968 handleLocationChangedLocked(location, this);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800969 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700970 }
971
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700972 @Override
973 public void onReportLocation(List<Location> locations) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700974 if (mGnssManagerService == null) {
975 return;
976 }
Soonil Nagarkard334f7b2019-07-08 16:16:19 -0700977 synchronized (mLock) {
978 LocationProvider gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
979 if (gpsProvider == null || !gpsProvider.isUseableLocked()) {
980 Slog.w(TAG, "reportLocationBatch() called without user permission");
981 return;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800982 }
Soonil Nagarkard334f7b2019-07-08 16:16:19 -0700983
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700984 mGnssManagerService.onReportLocation(locations);
Soonil Nagarkard334f7b2019-07-08 16:16:19 -0700985 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700986 }
987
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700988 @Override
989 public void onSetEnabled(boolean enabled) {
Soonil Nagarkard334f7b2019-07-08 16:16:19 -0700990 synchronized (mLock) {
991 if (enabled == mEnabled) {
992 return;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800993 }
Soonil Nagarkard334f7b2019-07-08 16:16:19 -0700994
995 if (D) {
996 Log.d(TAG, mName + " provider enabled is now " + mEnabled);
997 }
998
999 mEnabled = enabled;
1000 onUseableChangedLocked(false);
1001 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001002 }
1003
1004 @Override
1005 public void onSetProperties(ProviderProperties properties) {
Soonil Nagarkar66c0bac2019-01-15 13:36:44 -08001006 synchronized (mLock) {
1007 mProperties = properties;
1008 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001009 }
1010
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001011 @GuardedBy("mLock")
1012 public void onLocationModeChangedLocked() {
Soonil Nagarkar4ee3ac22019-02-08 19:19:24 -08001013 onUseableChangedLocked(false);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001014 }
1015
1016 @GuardedBy("mLock")
1017 public void onAllowedChangedLocked() {
1018 if (mIsManagedBySettings) {
Soonil Nagarkarb8466b72019-10-25 14:10:30 -07001019 boolean allowed = mSettingsStore.getLocationProvidersAllowed(
1020 mCurrentUserId).contains(mName);
Soonil Nagarkar4ee3ac22019-02-08 19:19:24 -08001021
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001022 if (allowed == mAllowed) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001023 return;
1024 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001025
Soonil Nagarkar4ee3ac22019-02-08 19:19:24 -08001026 if (D) {
1027 Log.d(TAG, mName + " provider allowed is now " + mAllowed);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001028 }
1029
Soonil Nagarkar4ee3ac22019-02-08 19:19:24 -08001030 mAllowed = allowed;
1031 onUseableChangedLocked(true);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001032 }
1033 }
1034
1035 @GuardedBy("mLock")
1036 public boolean isUseableLocked() {
1037 return isUseableForUserLocked(mCurrentUserId);
1038 }
1039
1040 @GuardedBy("mLock")
1041 public boolean isUseableForUserLocked(int userId) {
Soonil Nagarkar497c1cb2019-03-04 16:22:39 -08001042 return isCurrentProfileLocked(userId) && mUseable;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001043 }
1044
1045 @GuardedBy("mLock")
Soonil Nagarkar4ee3ac22019-02-08 19:19:24 -08001046 private boolean isUseableIgnoringAllowedLocked() {
1047 return mProvider != null && mProviders.contains(this) && isLocationEnabled()
1048 && mEnabled;
1049 }
1050
1051 @GuardedBy("mLock")
1052 public void onUseableChangedLocked(boolean isAllowedChanged) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001053 // if any property that contributes to "useability" here changes state, it MUST result
1054 // in a direct or indrect call to onUseableChangedLocked. this allows the provider to
1055 // guarantee that it will always eventually reach the correct state.
Soonil Nagarkar4ee3ac22019-02-08 19:19:24 -08001056 boolean useableIgnoringAllowed = isUseableIgnoringAllowedLocked();
1057 boolean useable = useableIgnoringAllowed && mAllowed;
1058
1059 // update deprecated provider allowed settings for backwards compatibility, and do this
1060 // even if there is no change in overall useability state. this may result in trying to
1061 // overwrite the same value, but Settings handles deduping this.
1062 if (mIsManagedBySettings) {
1063 // a "-" change derived from the allowed setting should not be overwritten, but a
1064 // "+" change should be corrected if necessary
1065 if (useableIgnoringAllowed && !isAllowedChanged) {
1066 Settings.Secure.putStringForUser(
1067 mContext.getContentResolver(),
1068 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1069 "+" + mName,
1070 mCurrentUserId);
1071 } else if (!useableIgnoringAllowed) {
1072 Settings.Secure.putStringForUser(
1073 mContext.getContentResolver(),
1074 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1075 "-" + mName,
1076 mCurrentUserId);
1077 }
Soonil Nagarkar3126c902019-03-04 18:29:49 -08001078
1079 // needs to be sent to all users because whether or not a provider is enabled for
1080 // a given user is complicated... we broadcast to everyone and let them figure it
1081 // out via isProviderEnabled()
1082 Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION);
1083 intent.putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName);
1084 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
Soonil Nagarkar4ee3ac22019-02-08 19:19:24 -08001085 }
1086
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001087 if (useable == mUseable) {
1088 return;
1089 }
1090 mUseable = useable;
1091
Soonil Nagarkar4ee3ac22019-02-08 19:19:24 -08001092 if (D) {
1093 Log.d(TAG, mName + " provider useable is now " + mUseable);
1094 }
1095
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001096 if (!mUseable) {
1097 // If any provider has been disabled, clear all last locations for all
1098 // providers. This is to be on the safe side in case a provider has location
1099 // derived from this disabled provider.
1100 mLastLocation.clear();
1101 mLastLocationCoarseInterval.clear();
1102 }
1103
1104 updateProviderUseableLocked(this);
1105 }
1106
1107 @GuardedBy("mLock")
1108 public void onUserChangingLocked() {
1109 // when the user is about to change, we set this provider to un-useable, and notify all
1110 // of the current user clients. when the user is finished changing, useability will be
1111 // updated back via onLocationModeChanged() and onAllowedChanged().
1112 mUseable = false;
1113 updateProviderUseableLocked(this);
1114 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001115 }
1116
1117 private class MockLocationProvider extends LocationProvider {
1118
Kweku Adams4fb074e2019-02-01 16:03:27 -08001119 private ProviderRequest mCurrentRequest;
1120
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001121 private MockLocationProvider(String name) {
1122 super(name);
1123 }
1124
1125 @Override
1126 public void attachLocked(AbstractLocationProvider provider) {
1127 checkState(provider instanceof MockProvider);
1128 super.attachLocked(provider);
1129 }
1130
1131 public boolean isMock() {
1132 return true;
1133 }
1134
1135 @GuardedBy("mLock")
1136 public void setEnabledLocked(boolean enabled) {
1137 if (mProvider != null) {
1138 long identity = Binder.clearCallingIdentity();
1139 try {
1140 ((MockProvider) mProvider).setEnabled(enabled);
1141 } finally {
1142 Binder.restoreCallingIdentity(identity);
Soonil Nagarkar68257742019-01-09 19:42:34 +00001143 }
1144 }
1145 }
1146
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001147 @GuardedBy("mLock")
1148 public void setLocationLocked(Location location) {
1149 if (mProvider != null) {
1150 long identity = Binder.clearCallingIdentity();
1151 try {
1152 ((MockProvider) mProvider).setLocation(location);
1153 } finally {
1154 Binder.restoreCallingIdentity(identity);
1155 }
1156 }
1157 }
1158
Kweku Adams4fb074e2019-02-01 16:03:27 -08001159 @Override
Soonil Nagarkard334f7b2019-07-08 16:16:19 -07001160 public void setRequest(ProviderRequest request, WorkSource workSource) {
1161 super.setRequest(request, workSource);
Kweku Adams4fb074e2019-02-01 16:03:27 -08001162 mCurrentRequest = request;
1163 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001164 }
1165
Victoria Lease38389b62012-09-30 11:44:22 -07001166 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001167 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
1168 * location updates.
1169 */
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07001170 private final class Receiver extends LocationManagerServiceUtils.LinkedListenerBase implements
1171 PendingIntent.OnFinished {
Yu-Han Yang24189822018-07-11 15:24:11 -07001172 private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001173 private final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001174
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001175 private final ILocationListener mListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -07001177 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001178 private final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
1179 private final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001180
gomo48f1a642017-11-10 20:35:46 -08001181 final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
Nick Pellyf1be6862012-05-15 10:53:42 -07001182
David Christie0b837452013-07-29 16:02:13 -07001183 // True if app ops has started monitoring this receiver for locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001184 private boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -07001185 // True if app ops has started monitoring this receiver for high power (gps) locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001186 private boolean mOpHighPowerMonitoring;
1187 private int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -07001188 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001190 private Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07001191 String packageName, @Nullable String featureId, WorkSource workSource,
1192 boolean hideFromAppOps, @NonNull String listenerIdentifier) {
1193 super(new CallerIdentity(uid, pid, packageName, featureId, listenerIdentifier),
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -07001194 "LocationListener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001197 if (listener != null) {
1198 mKey = listener.asBinder();
1199 } else {
1200 mKey = intent;
1201 }
Victoria Lease37425c32012-10-16 16:08:48 -07001202 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Narayan Kamath32684dd2018-01-08 17:32:51 +00001203 if (workSource != null && workSource.isEmpty()) {
David Christie82edc9b2013-07-19 11:31:42 -07001204 workSource = null;
1205 }
1206 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -07001207 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -07001208
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001209 updateMonitoring(true);
1210
Victoria Lease0aa28602013-05-29 15:28:26 -07001211 // construct/configure wakelock
1212 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -07001213 if (workSource == null) {
Anil Admal08b96122019-01-30 16:55:05 -08001214 workSource = new WorkSource(mCallerIdentity.mUid, mCallerIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07001215 }
1216 mWakeLock.setWorkSource(workSource);
Yu-Han Yang24189822018-07-11 15:24:11 -07001217
1218 // For a non-reference counted wakelock, each acquire will reset the timeout, and we
1219 // only need to release it once.
1220 mWakeLock.setReferenceCounted(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001221 }
1222
1223 @Override
1224 public boolean equals(Object otherObj) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001225 return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 }
1227
1228 @Override
1229 public int hashCode() {
1230 return mKey.hashCode();
1231 }
Mike Lockwood3681f262009-05-12 10:52:03 -04001232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001233 @Override
1234 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001235 StringBuilder s = new StringBuilder();
1236 s.append("Reciever[");
1237 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001238 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001239 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001240 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001241 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001242 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001243 for (String p : mUpdateRecords.keySet()) {
1244 s.append(" ").append(mUpdateRecords.get(p).toString());
1245 }
Wei Wangdd070f22018-06-21 11:29:40 -07001246 s.append(" monitoring location: ").append(mOpMonitoring);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001247 s.append("]");
1248 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001249 }
1250
David Christie15b31912013-08-13 15:54:32 -07001251 /**
1252 * Update AppOp monitoring for this receiver.
1253 *
1254 * @param allow If true receiver is currently active, if false it's been removed.
1255 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001256 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -07001257 if (mHideFromAppOps) {
1258 return;
1259 }
1260
David Christie15b31912013-08-13 15:54:32 -07001261 boolean requestingLocation = false;
1262 boolean requestingHighPowerLocation = false;
1263 if (allow) {
1264 // See if receiver has any enabled update records. Also note if any update records
1265 // are high power (has a high power provider with an interval under a threshold).
1266 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001267 LocationProvider provider = getLocationProviderLocked(updateRecord.mProvider);
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08001268 if (provider == null) {
1269 continue;
1270 }
Soonil Nagarkar397ad582019-01-23 22:47:57 -08001271 if (!provider.isUseableLocked() && !isSettingsExemptLocked(updateRecord)) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001272 continue;
1273 }
1274
1275 requestingLocation = true;
1276 ProviderProperties properties = provider.getPropertiesLocked();
1277 if (properties != null
1278 && properties.mPowerRequirement == Criteria.POWER_HIGH
1279 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
1280 requestingHighPowerLocation = true;
1281 break;
David Christie15b31912013-08-13 15:54:32 -07001282 }
1283 }
1284 }
1285
David Christie0b837452013-07-29 16:02:13 -07001286 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -07001287 mOpMonitoring = updateMonitoring(
1288 requestingLocation,
1289 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001290 AppOpsManager.OP_MONITOR_LOCATION);
1291
1292 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -07001293 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -07001294 mOpHighPowerMonitoring = updateMonitoring(
1295 requestingHighPowerLocation,
1296 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001297 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -07001298 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -07001299 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -07001300 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
1301 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1302 }
David Christie0b837452013-07-29 16:02:13 -07001303 }
1304
1305 /**
1306 * Update AppOps monitoring for a single location request and op type.
1307 *
gomo48f1a642017-11-10 20:35:46 -08001308 * @param allowMonitoring True if monitoring is allowed for this request/op.
David Christie0b837452013-07-29 16:02:13 -07001309 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
gomo48f1a642017-11-10 20:35:46 -08001310 * @param op AppOps code for the op to update.
David Christie0b837452013-07-29 16:02:13 -07001311 * @return True if monitoring is on for this request/op after updating.
1312 */
1313 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
1314 int op) {
1315 if (!currentlyMonitoring) {
1316 if (allowMonitoring) {
Anil Admal08b96122019-01-30 16:55:05 -08001317 return mAppOps.startOpNoThrow(op, mCallerIdentity.mUid,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07001318 mCallerIdentity.mPackageName, false, mCallerIdentity.mFeatureId, null)
1319 == AppOpsManager.MODE_ALLOWED;
David Christie0b837452013-07-29 16:02:13 -07001320 }
1321 } else {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001322 if (!allowMonitoring
Wei Wang16276a42019-02-04 18:23:31 -08001323 || mAppOps.checkOpNoThrow(op, mCallerIdentity.mUid,
Anil Admal08b96122019-01-30 16:55:05 -08001324 mCallerIdentity.mPackageName) != AppOpsManager.MODE_ALLOWED) {
1325 mAppOps.finishOp(op, mCallerIdentity.mUid, mCallerIdentity.mPackageName);
David Christie0b837452013-07-29 16:02:13 -07001326 return false;
1327 }
1328 }
1329
1330 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001331 }
1332
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333 public boolean isListener() {
1334 return mListener != null;
1335 }
1336
1337 public boolean isPendingIntent() {
1338 return mPendingIntent != null;
1339 }
1340
1341 public ILocationListener getListener() {
1342 if (mListener != null) {
1343 return mListener;
1344 }
1345 throw new IllegalStateException("Request for non-existent listener");
1346 }
1347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001348 public boolean callLocationChangedLocked(Location location) {
1349 if (mListener != null) {
1350 try {
Soonil Nagarkarb46c1672019-02-06 12:49:10 -08001351 mListener.onLocationChanged(new Location(location));
1352 // call this after broadcasting so we do not increment
1353 // if we throw an exception.
1354 incrementPendingBroadcastsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001355 } catch (RemoteException e) {
1356 return false;
1357 }
1358 } else {
1359 Intent locationChanged = new Intent();
gomo48f1a642017-11-10 20:35:46 -08001360 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED,
1361 new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001362 try {
Soonil Nagarkarb46c1672019-02-06 12:49:10 -08001363 mPendingIntent.send(mContext, 0, locationChanged, this, mHandler,
1364 getResolutionPermission(mAllowedResolutionLevel),
1365 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
1366 // call this after broadcasting so we do not increment
1367 // if we throw an exception.
1368 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001369 } catch (PendingIntent.CanceledException e) {
1370 return false;
1371 }
1372 }
1373 return true;
1374 }
1375
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001376 private boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -07001377 // First update AppOp monitoring.
1378 // An app may get/lose location access as providers are enabled/disabled.
1379 updateMonitoring(true);
1380
Mike Lockwood48f17512009-04-23 09:12:08 -07001381 if (mListener != null) {
1382 try {
Soonil Nagarkarb46c1672019-02-06 12:49:10 -08001383 if (enabled) {
1384 mListener.onProviderEnabled(provider);
1385 } else {
1386 mListener.onProviderDisabled(provider);
Mike Lockwood48f17512009-04-23 09:12:08 -07001387 }
Soonil Nagarkarb46c1672019-02-06 12:49:10 -08001388 // call this after broadcasting so we do not increment
1389 // if we throw an exception.
1390 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001391 } catch (RemoteException e) {
1392 return false;
1393 }
1394 } else {
1395 Intent providerIntent = new Intent();
1396 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
1397 try {
Soonil Nagarkarb46c1672019-02-06 12:49:10 -08001398 mPendingIntent.send(mContext, 0, providerIntent, this, mHandler,
1399 getResolutionPermission(mAllowedResolutionLevel),
1400 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
1401 // call this after broadcasting so we do not increment
1402 // if we throw an exception.
1403 incrementPendingBroadcastsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 } catch (PendingIntent.CanceledException e) {
1405 return false;
1406 }
1407 }
1408 return true;
1409 }
1410
Soonil Nagarkar39d614a2019-10-31 12:10:31 -07001411 public void callRemovedLocked() {
1412 if (mListener != null) {
1413 try {
1414 mListener.onRemoved();
1415 } catch (RemoteException e) {
1416 // doesn't matter
1417 }
1418 }
1419 }
1420
Nick Pellyf1be6862012-05-15 10:53:42 -07001421 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 public void binderDied() {
Anil Admal98d49b72019-02-06 15:26:33 -08001423 if (D) Log.d(TAG, "Remote " + mListenerName + " died.");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001424
Soonil Nagarkar68257742019-01-09 19:42:34 +00001425 synchronized (mLock) {
1426 removeUpdatesLocked(this);
Soonil Nagarkar68257742019-01-09 19:42:34 +00001427 clearPendingBroadcastsLocked();
1428 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001429 }
1430
Nick Pellye0fd6932012-07-11 10:26:13 -07001431 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001432 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1433 int resultCode, String resultData, Bundle resultExtras) {
Soonil Nagarkarb46c1672019-02-06 12:49:10 -08001434 synchronized (mLock) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001435 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001436 }
1437 }
1438
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001439 // this must be called while synchronized by caller in a synchronized block
1440 // containing the sending of the broadcaset
1441 private void incrementPendingBroadcastsLocked() {
Yu-Han Yang24189822018-07-11 15:24:11 -07001442 mPendingBroadcasts++;
Soonil Nagarkarb46c1672019-02-06 12:49:10 -08001443 // so wakelock calls will succeed
1444 long identity = Binder.clearCallingIdentity();
1445 try {
1446 mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
1447 } finally {
1448 Binder.restoreCallingIdentity(identity);
1449 }
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001450 }
1451
1452 private void decrementPendingBroadcastsLocked() {
1453 if (--mPendingBroadcasts == 0) {
Soonil Nagarkarb46c1672019-02-06 12:49:10 -08001454 // so wakelock calls will succeed
1455 long identity = Binder.clearCallingIdentity();
1456 try {
1457 if (mWakeLock.isHeld()) {
1458 mWakeLock.release();
1459 }
1460 } finally {
1461 Binder.restoreCallingIdentity(identity);
Victoria Lease0aa28602013-05-29 15:28:26 -07001462 }
1463 }
1464 }
1465
1466 public void clearPendingBroadcastsLocked() {
1467 if (mPendingBroadcasts > 0) {
1468 mPendingBroadcasts = 0;
Soonil Nagarkarb46c1672019-02-06 12:49:10 -08001469 // so wakelock calls will succeed
1470 long identity = Binder.clearCallingIdentity();
1471 try {
1472 if (mWakeLock.isHeld()) {
1473 mWakeLock.release();
1474 }
1475 } finally {
1476 Binder.restoreCallingIdentity(identity);
Victoria Lease0aa28602013-05-29 15:28:26 -07001477 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001478 }
1479 }
1480 }
1481
Nick Pellye0fd6932012-07-11 10:26:13 -07001482 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001483 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001484 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -04001485 //the receiver list if it is not found. If it is not found then the
1486 //LocationListener was removed when it had a pending broadcast and should
1487 //not be added back.
Soonil Nagarkar68257742019-01-09 19:42:34 +00001488 synchronized (mLock) {
Soonil Nagarkarb46c1672019-02-06 12:49:10 -08001489 Receiver receiver = mReceivers.get(listener.asBinder());
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001490 if (receiver != null) {
Soonil Nagarkarb46c1672019-02-06 12:49:10 -08001491 receiver.decrementPendingBroadcastsLocked();
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001492 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00001493 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001494 }
1495
Lifu Tang82f893d2016-01-21 18:15:33 -08001496 @Override
Lifu Tang9363b942016-02-16 18:07:00 -08001497 public int getGnssYearOfHardware() {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07001498 return mGnssManagerService == null ? 0 : mGnssManagerService.getGnssYearOfHardware();
Lifu Tang82f893d2016-01-21 18:15:33 -08001499 }
1500
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001501 @Override
Wyatt Riley49097c02018-03-15 09:14:43 -07001502 @Nullable
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001503 public String getGnssHardwareModelName() {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07001504 return mGnssManagerService == null ? "" : mGnssManagerService.getGnssHardwareModelName();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001505 }
1506
Wyatt Rileycf879db2017-01-12 13:57:38 -08001507 @Override
1508 public int getGnssBatchSize(String packageName) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07001509 return mGnssManagerService == null ? 0 : mGnssManagerService.getGnssBatchSize(packageName);
Wyatt Rileycf879db2017-01-12 13:57:38 -08001510 }
1511
Wyatt Rileycf879db2017-01-12 13:57:38 -08001512 @Override
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -07001513 public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07001514 String featureId, String listenerIdentifier) {
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -07001515 Preconditions.checkNotNull(listenerIdentifier);
1516
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07001517 return mGnssManagerService == null ? false : mGnssManagerService.addGnssBatchingCallback(
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07001518 callback, packageName, featureId, listenerIdentifier);
Wyatt Rileycf879db2017-01-12 13:57:38 -08001519 }
1520
Wyatt Rileycf879db2017-01-12 13:57:38 -08001521 @Override
1522 public void removeGnssBatchingCallback() {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07001523 if (mGnssManagerService != null) mGnssManagerService.removeGnssBatchingCallback();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001524 }
1525
Wyatt Rileycf879db2017-01-12 13:57:38 -08001526 @Override
1527 public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07001528 return mGnssManagerService == null ? false : mGnssManagerService.startGnssBatch(periodNanos,
1529 wakeOnFifoFull, packageName);
Wyatt Rileycf879db2017-01-12 13:57:38 -08001530 }
1531
Wyatt Rileycf879db2017-01-12 13:57:38 -08001532 @Override
1533 public void flushGnssBatch(String packageName) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07001534 if (mGnssManagerService != null) mGnssManagerService.flushGnssBatch(packageName);
Wyatt Rileycf879db2017-01-12 13:57:38 -08001535 }
1536
Wyatt Rileycf879db2017-01-12 13:57:38 -08001537 @Override
1538 public boolean stopGnssBatch() {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07001539 return mGnssManagerService == null ? false : mGnssManagerService.stopGnssBatch();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001540 }
1541
1542 @GuardedBy("mLock")
1543 private void addProviderLocked(LocationProvider provider) {
1544 Preconditions.checkState(getLocationProviderLocked(provider.getName()) == null);
1545
1546 mProviders.add(provider);
1547
1548 provider.onAllowedChangedLocked(); // allowed state may change while provider was inactive
Soonil Nagarkar4ee3ac22019-02-08 19:19:24 -08001549 provider.onUseableChangedLocked(false);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001550 }
1551
1552 @GuardedBy("mLock")
1553 private void removeProviderLocked(LocationProvider provider) {
1554 if (mProviders.remove(provider)) {
Soonil Nagarkar04cff6c2019-03-19 11:29:52 -07001555 provider.onUseableChangedLocked(false);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001556 }
1557 }
1558
1559 @GuardedBy("mLock")
1560 @Nullable
1561 private LocationProvider getLocationProviderLocked(String providerName) {
1562 for (LocationProvider provider : mProviders) {
1563 if (providerName.equals(provider.getName())) {
1564 return provider;
Soonil Nagarkar68257742019-01-09 19:42:34 +00001565 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001566 }
1567
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001568 return null;
Maggie2a9409e2018-03-21 11:47:28 -07001569 }
1570
Victoria Lease37425c32012-10-16 16:08:48 -07001571 private String getResolutionPermission(int resolutionLevel) {
1572 switch (resolutionLevel) {
1573 case RESOLUTION_LEVEL_FINE:
1574 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1575 case RESOLUTION_LEVEL_COARSE:
1576 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1577 default:
1578 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001579 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001580 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001581
Victoria Lease37425c32012-10-16 16:08:48 -07001582 private int getAllowedResolutionLevel(int pid, int uid) {
1583 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001584 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001585 return RESOLUTION_LEVEL_FINE;
1586 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001587 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001588 return RESOLUTION_LEVEL_COARSE;
1589 } else {
1590 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001591 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001592 }
1593
Victoria Lease37425c32012-10-16 16:08:48 -07001594 private int getCallerAllowedResolutionLevel() {
1595 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1596 }
1597
Victoria Lease37425c32012-10-16 16:08:48 -07001598 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1599 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001600 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1601 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001602 }
1603
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001604 @GuardedBy("mLock")
1605 private int getMinimumResolutionLevelForProviderUseLocked(String provider) {
1606 if (GPS_PROVIDER.equals(provider) || PASSIVE_PROVIDER.equals(provider)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001607 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001608 return RESOLUTION_LEVEL_FINE;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001609 } else if (NETWORK_PROVIDER.equals(provider) || FUSED_PROVIDER.equals(provider)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001610 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001611 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001612 } else {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001613 for (LocationProvider lp : mProviders) {
1614 if (!lp.getName().equals(provider)) {
1615 continue;
1616 }
1617
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001618 ProviderProperties properties = lp.getPropertiesLocked();
Laurent Tu941221c2012-10-04 14:21:52 -07001619 if (properties != null) {
1620 if (properties.mRequiresSatellite) {
1621 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001622 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001623 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1624 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001625 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001626 }
1627 }
1628 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001629 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001630
Victoria Lease37425c32012-10-16 16:08:48 -07001631 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001632 }
1633
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001634 @GuardedBy("mLock")
1635 private void checkResolutionLevelIsSufficientForProviderUseLocked(int allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001636 String providerName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001637 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUseLocked(providerName);
Victoria Lease37425c32012-10-16 16:08:48 -07001638 if (allowedResolutionLevel < requiredResolutionLevel) {
1639 switch (requiredResolutionLevel) {
1640 case RESOLUTION_LEVEL_FINE:
1641 throw new SecurityException("\"" + providerName + "\" location provider " +
1642 "requires ACCESS_FINE_LOCATION permission.");
1643 case RESOLUTION_LEVEL_COARSE:
1644 throw new SecurityException("\"" + providerName + "\" location provider " +
1645 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1646 default:
1647 throw new SecurityException("Insufficient permission for \"" + providerName +
1648 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001649 }
1650 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001651 }
1652
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001653 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001654 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1655 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001656 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001657 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001658 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001659 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001660 }
1661 return -1;
1662 }
1663
Wei Wangb86334f2018-07-03 16:33:24 -07001664 private static String resolutionLevelToOpStr(int allowedResolutionLevel) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001665 switch (allowedResolutionLevel) {
Wei Wangb86334f2018-07-03 16:33:24 -07001666 case RESOLUTION_LEVEL_COARSE:
1667 return AppOpsManager.OPSTR_COARSE_LOCATION;
1668 case RESOLUTION_LEVEL_FINE:
1669 return AppOpsManager.OPSTR_FINE_LOCATION;
1670 case RESOLUTION_LEVEL_NONE:
1671 // The client is not allowed to get any location, so both FINE and COARSE ops will
1672 // be denied. Pick the most restrictive one to be safe.
1673 return AppOpsManager.OPSTR_FINE_LOCATION;
1674 default:
1675 // Use the most restrictive ops if not sure.
1676 return AppOpsManager.OPSTR_FINE_LOCATION;
1677 }
1678 }
1679
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -07001680 private boolean reportLocationAccessNoThrow(int pid, int uid, String packageName,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07001681 @Nullable String featureId, int allowedResolutionLevel, @Nullable String message) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001682 int op = resolutionLevelToOp(allowedResolutionLevel);
1683 if (op >= 0) {
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07001684 if (mAppOps.noteOpNoThrow(op, uid, packageName, featureId, message)
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -07001685 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001686 return false;
1687 }
1688 }
David Christieb870dbf2015-06-22 12:42:53 -07001689
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001690 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001691 }
1692
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001693 private boolean checkLocationAccess(int pid, int uid, String packageName,
1694 int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001695 int op = resolutionLevelToOp(allowedResolutionLevel);
1696 if (op >= 0) {
Wei Wang16276a42019-02-04 18:23:31 -08001697 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001698 return false;
1699 }
1700 }
David Christieb870dbf2015-06-22 12:42:53 -07001701
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001702 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001703 }
1704
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001705 /**
Maggie91e630c2018-01-24 17:31:46 -08001706 * Returns all providers by name, including passive and the ones that are not permitted to
1707 * be accessed by the calling activity or are currently disabled, but excluding fused.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001708 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001709 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001710 public List<String> getAllProviders() {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001711 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001712 ArrayList<String> providers = new ArrayList<>(mProviders.size());
Soonil Nagarkar68257742019-01-09 19:42:34 +00001713 for (LocationProvider provider : mProviders) {
1714 String name = provider.getName();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001715 if (FUSED_PROVIDER.equals(name)) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001716 continue;
1717 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001718 providers.add(name);
Maggie91e630c2018-01-24 17:31:46 -08001719 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001720 return providers;
Maggie91e630c2018-01-24 17:31:46 -08001721 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722 }
1723
Mike Lockwood03ca2162010-04-01 08:10:09 -07001724 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001725 * Return all providers by name, that match criteria and are optionally
1726 * enabled.
1727 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001728 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001729 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001730 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001731 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001732 synchronized (mLock) {
1733 ArrayList<String> providers = new ArrayList<>(mProviders.size());
1734 for (LocationProvider provider : mProviders) {
1735 String name = provider.getName();
1736 if (FUSED_PROVIDER.equals(name)) {
1737 continue;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001738 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001739 if (allowedResolutionLevel < getMinimumResolutionLevelForProviderUseLocked(name)) {
1740 continue;
1741 }
1742 if (enabledOnly && !provider.isUseableLocked()) {
1743 continue;
1744 }
1745 if (criteria != null
1746 && !android.location.LocationProvider.propertiesMeetCriteria(
1747 name, provider.getPropertiesLocked(), criteria)) {
1748 continue;
1749 }
1750 providers.add(name);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001751 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001752 return providers;
Soonil Nagarkar68257742019-01-09 19:42:34 +00001753 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001754 }
1755
1756 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001757 * Return the name of the best provider given a Criteria object.
1758 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001759 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001760 * has been deprecated as well. So this method now uses
1761 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001762 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001763 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001764 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001765 List<String> providers = getProviders(criteria, enabledOnly);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001766 if (providers.isEmpty()) {
1767 providers = getProviders(null, enabledOnly);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001768 }
1769
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001770 if (!providers.isEmpty()) {
1771 if (providers.contains(GPS_PROVIDER)) {
1772 return GPS_PROVIDER;
1773 } else if (providers.contains(NETWORK_PROVIDER)) {
1774 return NETWORK_PROVIDER;
1775 } else {
1776 return providers.get(0);
1777 }
1778 }
1779
Mike Lockwood03ca2162010-04-01 08:10:09 -07001780 return null;
1781 }
1782
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001783 @GuardedBy("mLock")
1784 private void updateProviderUseableLocked(LocationProvider provider) {
1785 boolean useable = provider.isUseableLocked();
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001786
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001787 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001788
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001789 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790 if (records != null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001791 for (UpdateRecord record : records) {
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08001792 if (!isCurrentProfileLocked(
Anil Admal08b96122019-01-30 16:55:05 -08001793 UserHandle.getUserId(record.mReceiver.mCallerIdentity.mUid))) {
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08001794 continue;
1795 }
1796
Kweku Adams5e0052b2019-02-22 15:17:52 -08001797 // requests that ignore location settings will never provide notifications
Soonil Nagarkar397ad582019-01-23 22:47:57 -08001798 if (isSettingsExemptLocked(record)) {
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08001799 continue;
1800 }
1801
1802 // Sends a notification message to the receiver
1803 if (!record.mReceiver.callProviderEnabledLocked(provider.getName(), useable)) {
1804 if (deadReceivers == null) {
1805 deadReceivers = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 }
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08001807 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001808 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001809 }
1810 }
1811
1812 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001813 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001814 removeUpdatesLocked(deadReceivers.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001815 }
1816 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001817
Soonil Nagarkar68257742019-01-09 19:42:34 +00001818 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001819 }
1820
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001821 @GuardedBy("mLock")
1822 private void applyRequirementsLocked(String providerName) {
1823 LocationProvider provider = getLocationProviderLocked(providerName);
1824 if (provider != null) {
1825 applyRequirementsLocked(provider);
1826 }
1827 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001828
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001829 @GuardedBy("mLock")
1830 private void applyRequirementsLocked(LocationProvider provider) {
1831 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001832 WorkSource worksource = new WorkSource();
1833 ProviderRequest providerRequest = new ProviderRequest();
1834
Soonil Nagarkar04cff6c2019-03-19 11:29:52 -07001835 // if provider is not active, it should not respond to requests
1836
1837 if (mProviders.contains(provider) && records != null && !records.isEmpty()) {
Kweku Adams5e0052b2019-02-22 15:17:52 -08001838 long backgroundThrottleInterval;
1839
1840 long identity = Binder.clearCallingIdentity();
1841 try {
Soonil Nagarkarb8466b72019-10-25 14:10:30 -07001842 backgroundThrottleInterval = mSettingsStore.getBackgroundThrottleIntervalMs();
Kweku Adams5e0052b2019-02-22 15:17:52 -08001843 } finally {
1844 Binder.restoreCallingIdentity(identity);
1845 }
1846
1847 final boolean isForegroundOnlyMode =
Kweku Adams4fb074e2019-02-01 16:03:27 -08001848 mBatterySaverMode == PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
1849 final boolean shouldThrottleRequests =
1850 mBatterySaverMode
1851 == PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF
1852 && !mPowerManager.isInteractive();
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001853 // initialize the low power mode to true and set to false if any of the records requires
1854 providerRequest.lowPowerMode = true;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001855 for (UpdateRecord record : records) {
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08001856 if (!isCurrentProfileLocked(
Anil Admal08b96122019-01-30 16:55:05 -08001857 UserHandle.getUserId(record.mReceiver.mCallerIdentity.mUid))) {
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08001858 continue;
1859 }
1860 if (!checkLocationAccess(
Anil Admal08b96122019-01-30 16:55:05 -08001861 record.mReceiver.mCallerIdentity.mPid,
1862 record.mReceiver.mCallerIdentity.mUid,
1863 record.mReceiver.mCallerIdentity.mPackageName,
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08001864 record.mReceiver.mAllowedResolutionLevel)) {
1865 continue;
1866 }
Kweku Adams4fb074e2019-02-01 16:03:27 -08001867 final boolean isBatterySaverDisablingLocation = shouldThrottleRequests
1868 || (isForegroundOnlyMode && !record.mIsForegroundUid);
Kweku Adams5e0052b2019-02-22 15:17:52 -08001869 if (!provider.isUseableLocked() || isBatterySaverDisablingLocation) {
Soonil Nagarkar35c3b912019-01-31 10:31:24 -08001870 if (isSettingsExemptLocked(record)) {
Soonil Nagarkar509580f2019-02-06 15:57:26 -08001871 providerRequest.locationSettingsIgnored = true;
Soonil Nagarkarb46c1672019-02-06 12:49:10 -08001872 providerRequest.lowPowerMode = false;
Soonil Nagarkar35c3b912019-01-31 10:31:24 -08001873 } else {
1874 continue;
1875 }
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08001876 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001877
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08001878 LocationRequest locationRequest = record.mRealRequest;
1879 long interval = locationRequest.getInterval();
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001880
Soonil Nagarkar509580f2019-02-06 15:57:26 -08001881
Soonil Nagarkarb46c1672019-02-06 12:49:10 -08001882 // if we're forcing location, don't apply any throttling
Soonil Nagarkar509580f2019-02-06 15:57:26 -08001883 if (!providerRequest.locationSettingsIgnored && !isThrottlingExemptLocked(
Soonil Nagarkarb46c1672019-02-06 12:49:10 -08001884 record.mReceiver.mCallerIdentity)) {
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08001885 if (!record.mIsForegroundUid) {
1886 interval = Math.max(interval, backgroundThrottleInterval);
Victoria Leaseb711d572012-10-02 13:14:11 -07001887 }
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08001888 if (interval != locationRequest.getInterval()) {
1889 locationRequest = new LocationRequest(locationRequest);
1890 locationRequest.setInterval(interval);
1891 }
1892 }
1893
1894 record.mRequest = locationRequest;
1895 providerRequest.locationRequests.add(locationRequest);
1896 if (!locationRequest.isLowPowerMode()) {
1897 providerRequest.lowPowerMode = false;
1898 }
1899 if (interval < providerRequest.interval) {
1900 providerRequest.reportLocation = true;
1901 providerRequest.interval = interval;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001902 }
1903 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001904
1905 if (providerRequest.reportLocation) {
1906 // calculate who to blame for power
1907 // This is somewhat arbitrary. We pick a threshold interval
1908 // that is slightly higher that the minimum interval, and
1909 // spread the blame across all applications with a request
1910 // under that threshold.
1911 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1912 for (UpdateRecord record : records) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001913 if (isCurrentProfileLocked(
Anil Admal08b96122019-01-30 16:55:05 -08001914 UserHandle.getUserId(record.mReceiver.mCallerIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001915 LocationRequest locationRequest = record.mRequest;
Svet Ganove998c732016-06-10 00:12:38 -07001916
1917 // Don't assign battery blame for update records whose
1918 // client has no permission to receive location data.
1919 if (!providerRequest.locationRequests.contains(locationRequest)) {
1920 continue;
1921 }
1922
Victoria Leaseb711d572012-10-02 13:14:11 -07001923 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07001924 if (record.mReceiver.mWorkSource != null
Narayan Kamath32684dd2018-01-08 17:32:51 +00001925 && isValidWorkSource(record.mReceiver.mWorkSource)) {
David Christie82edc9b2013-07-19 11:31:42 -07001926 worksource.add(record.mReceiver.mWorkSource);
1927 } else {
Narayan Kamath32684dd2018-01-08 17:32:51 +00001928 // Assign blame to caller if there's no WorkSource associated with
1929 // the request or if it's invalid.
David Christie82edc9b2013-07-19 11:31:42 -07001930 worksource.add(
Anil Admal08b96122019-01-30 16:55:05 -08001931 record.mReceiver.mCallerIdentity.mUid,
1932 record.mReceiver.mCallerIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07001933 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001934 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001935 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001936 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001937 }
1938 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001939
Soonil Nagarkard334f7b2019-07-08 16:16:19 -07001940 provider.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001941 }
1942
Narayan Kamath32684dd2018-01-08 17:32:51 +00001943 /**
1944 * Whether a given {@code WorkSource} associated with a Location request is valid.
1945 */
1946 private static boolean isValidWorkSource(WorkSource workSource) {
1947 if (workSource.size() > 0) {
1948 // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
1949 // by tags.
Suprabh Shuklaf7cffa72019-11-08 17:03:03 -08001950 return workSource.getPackageName(0) != null;
Narayan Kamath32684dd2018-01-08 17:32:51 +00001951 } else {
1952 // For now, make sure callers have supplied an attribution tag for use with
1953 // AppOpsManager. This might be relaxed in the future.
Suprabh Shuklaf7cffa72019-11-08 17:03:03 -08001954 final List<WorkChain> workChains = workSource.getWorkChains();
Narayan Kamath32684dd2018-01-08 17:32:51 +00001955 return workChains != null && !workChains.isEmpty() &&
1956 workChains.get(0).getAttributionTag() != null;
1957 }
1958 }
1959
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001960 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001961 public String[] getBackgroundThrottlingWhitelist() {
Soonil Nagarkarb8466b72019-10-25 14:10:30 -07001962 return mSettingsStore.getBackgroundThrottlePackageWhitelist().toArray(new String[0]);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001963 }
1964
Soonil Nagarkar5140e4f2019-02-14 17:21:33 -08001965 @Override
1966 public String[] getIgnoreSettingsWhitelist() {
Soonil Nagarkarb8466b72019-10-25 14:10:30 -07001967 return mSettingsStore.getIgnoreSettingsPackageWhitelist().toArray(new String[0]);
Soonil Nagarkar5140e4f2019-02-14 17:21:33 -08001968 }
1969
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001970 @GuardedBy("mLock")
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07001971 public boolean isThrottlingExemptLocked(CallerIdentity callerIdentity) {
Anil Admal08b96122019-01-30 16:55:05 -08001972 if (callerIdentity.mUid == Process.SYSTEM_UID) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001973 return true;
1974 }
1975
Soonil Nagarkarb8466b72019-10-25 14:10:30 -07001976 if (mSettingsStore.getBackgroundThrottlePackageWhitelist().contains(
1977 callerIdentity.mPackageName)) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001978 return true;
1979 }
1980
Soonil Nagarkarb46c1672019-02-06 12:49:10 -08001981 return isProviderPackage(callerIdentity.mPackageName);
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001982
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001983 }
1984
Soonil Nagarkar397ad582019-01-23 22:47:57 -08001985 @GuardedBy("mLock")
1986 private boolean isSettingsExemptLocked(UpdateRecord record) {
1987 if (!record.mRealRequest.isLocationSettingsIgnored()) {
1988 return false;
1989 }
1990
Soonil Nagarkarb8466b72019-10-25 14:10:30 -07001991 if (mSettingsStore.getIgnoreSettingsPackageWhitelist().contains(
Anil Admal08b96122019-01-30 16:55:05 -08001992 record.mReceiver.mCallerIdentity.mPackageName)) {
Soonil Nagarkar397ad582019-01-23 22:47:57 -08001993 return true;
1994 }
1995
Soonil Nagarkarb46c1672019-02-06 12:49:10 -08001996 return isProviderPackage(record.mReceiver.mCallerIdentity.mPackageName);
Soonil Nagarkar397ad582019-01-23 22:47:57 -08001997
Soonil Nagarkar397ad582019-01-23 22:47:57 -08001998 }
1999
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002000 private class UpdateRecord {
2001 final String mProvider;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002002 private final LocationRequest mRealRequest; // original request from client
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002003 LocationRequest mRequest; // possibly throttled version of the request
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002004 private final Receiver mReceiver;
2005 private boolean mIsForegroundUid;
2006 private Location mLastFixBroadcast;
Soonil Nagarkarae6ce772019-05-01 13:16:17 -07002007 private Throwable mStackTrace; // for debugging only
Soonil Nagarkar95768ce2019-11-05 15:22:44 -08002008 private long mExpirationRealtimeMs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002009
2010 /**
2011 * Note: must be constructed with lock held.
2012 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002013 private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
Soonil Nagarkar95768ce2019-11-05 15:22:44 -08002014 mExpirationRealtimeMs = request.getExpirationRealtimeMs(SystemClock.elapsedRealtime());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002015 mProvider = provider;
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002016 mRealRequest = request;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002017 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002018 mReceiver = receiver;
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07002019 mIsForegroundUid =
2020 LocationManagerServiceUtils.isImportanceForeground(
2021 mActivityManager.getPackageImportance(
2022 mReceiver.mCallerIdentity.mPackageName));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002023
Soonil Nagarkarae6ce772019-05-01 13:16:17 -07002024 if (D && receiver.mCallerIdentity.mPid == Process.myPid()) {
2025 mStackTrace = new Throwable();
2026 }
2027
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002028 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2029 if (records == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002030 records = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002031 mRecordsByProvider.put(provider, records);
2032 }
2033 if (!records.contains(this)) {
2034 records.add(this);
2035 }
David Christie2ff96af2014-01-30 16:09:37 -08002036
2037 // Update statistics for historical location requests by package/provider
2038 mRequestStatistics.startRequesting(
Anil Admal08b96122019-01-30 16:55:05 -08002039 mReceiver.mCallerIdentity.mPackageName, provider, request.getInterval(),
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002040 mIsForegroundUid);
2041 }
2042
2043 /**
2044 * Method to be called when record changes foreground/background
2045 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002046 private void updateForeground(boolean isForeground) {
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002047 mIsForegroundUid = isForeground;
2048 mRequestStatistics.updateForeground(
Anil Admal08b96122019-01-30 16:55:05 -08002049 mReceiver.mCallerIdentity.mPackageName, mProvider, isForeground);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002050 }
2051
2052 /**
David Christie2ff96af2014-01-30 16:09:37 -08002053 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002055 private void disposeLocked(boolean removeReceiver) {
Hongyi Zhang700137e2019-05-23 21:19:36 -07002056 String packageName = mReceiver.mCallerIdentity.mPackageName;
2057 mRequestStatistics.stopRequesting(packageName, mProvider);
2058
2059 mLocationUsageLogger.logLocationApiUsage(
2060 LocationStatsEnums.USAGE_ENDED,
2061 LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
2062 packageName,
2063 mRealRequest,
2064 mReceiver.isListener(),
2065 mReceiver.isPendingIntent(),
Hongyi Zhang0e9ea752019-06-09 22:49:25 -07002066 /* geofence= */ null,
Hongyi Zhang700137e2019-05-23 21:19:36 -07002067 mActivityManager.getPackageImportance(packageName));
David Christie2ff96af2014-01-30 16:09:37 -08002068
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002069 // remove from mRecordsByProvider
2070 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
2071 if (globalRecords != null) {
2072 globalRecords.remove(this);
2073 }
2074
2075 if (!removeReceiver) return; // the caller will handle the rest
2076
2077 // remove from Receiver#mUpdateRecords
2078 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002079 receiverRecords.remove(this.mProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002080
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002081 // and also remove the Receiver if it has no more update records
2082 if (receiverRecords.size() == 0) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002083 removeUpdatesLocked(mReceiver);
Mike Lockwood3a76fd62009-09-01 07:26:56 -04002084 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002085 }
2086
2087 @Override
2088 public String toString() {
Soonil Nagarkarae6ce772019-05-01 13:16:17 -07002089 StringBuilder b = new StringBuilder("UpdateRecord[");
2090 b.append(mProvider).append(" ");
2091 b.append(mReceiver.mCallerIdentity.mPackageName);
2092 b.append("(").append(mReceiver.mCallerIdentity.mUid);
2093 if (mIsForegroundUid) {
2094 b.append(" foreground");
2095 } else {
2096 b.append(" background");
2097 }
2098 b.append(") ");
2099 b.append(mRealRequest).append(" ").append(mReceiver.mWorkSource);
2100
2101 if (mStackTrace != null) {
2102 ByteArrayOutputStream tmp = new ByteArrayOutputStream();
2103 mStackTrace.printStackTrace(new PrintStream(tmp));
2104 b.append("\n\n").append(tmp.toString()).append("\n");
2105 }
2106
2107 b.append("]");
2108 return b.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002109 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002110 }
2111
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002112 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002113 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002114 String packageName, @Nullable String featureId, WorkSource workSource,
2115 boolean hideFromAppOps, @NonNull String listenerIdentifier) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002116 IBinder binder = listener.asBinder();
2117 Receiver receiver = mReceivers.get(binder);
2118 if (receiver == null) {
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002119 receiver = new Receiver(listener, null, pid, uid, packageName, featureId, workSource,
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -07002120 hideFromAppOps, listenerIdentifier);
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07002121 if (!receiver.linkToListenerDeathNotificationLocked(
2122 receiver.getListener().asBinder())) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002123 return null;
2124 }
Wen Jingcb3ab222014-03-27 13:42:59 +08002125 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002126 }
2127 return receiver;
2128 }
2129
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002130 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002131 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002132 @Nullable String featureId, WorkSource workSource, boolean hideFromAppOps,
2133 @NonNull String listenerIdentifier) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002134 Receiver receiver = mReceivers.get(intent);
2135 if (receiver == null) {
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002136 receiver = new Receiver(null, intent, pid, uid, packageName, featureId, workSource,
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -07002137 hideFromAppOps, listenerIdentifier);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002138 mReceivers.put(intent, receiver);
2139 }
2140 return receiver;
2141 }
2142
Victoria Lease37425c32012-10-16 16:08:48 -07002143 /**
2144 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
2145 * and consistency requirements.
2146 *
2147 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07002148 * @return a version of request that meets the given resolution and consistency requirements
2149 * @hide
2150 */
gomo48f1a642017-11-10 20:35:46 -08002151 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel,
2152 boolean callerHasLocationHardwarePermission) {
Victoria Lease37425c32012-10-16 16:08:48 -07002153 LocationRequest sanitizedRequest = new LocationRequest(request);
gomo48f1a642017-11-10 20:35:46 -08002154 if (!callerHasLocationHardwarePermission) {
2155 // allow setting low power mode only for callers with location hardware permission
2156 sanitizedRequest.setLowPowerMode(false);
2157 }
Victoria Lease37425c32012-10-16 16:08:48 -07002158 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
2159 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002160 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07002161 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07002162 break;
2163 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07002164 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07002165 break;
2166 }
2167 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07002168 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2169 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002170 }
Victoria Lease37425c32012-10-16 16:08:48 -07002171 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2172 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002173 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002174 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002175 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07002176 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Soonil Nagarkar397ad582019-01-23 22:47:57 -08002177 sanitizedRequest.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002178 }
Victoria Lease37425c32012-10-16 16:08:48 -07002179 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002180 }
2181
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002182 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07002183 if (packageName == null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002184 throw new SecurityException("invalid package name: " + null);
Nick Pellye0fd6932012-07-11 10:26:13 -07002185 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002186 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07002187 String[] packages = mPackageManager.getPackagesForUid(uid);
2188 if (packages == null) {
2189 throw new SecurityException("invalid UID " + uid);
2190 }
2191 for (String pkg : packages) {
2192 if (packageName.equals(pkg)) return;
2193 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002194 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002195 }
2196
Nick Pellye0fd6932012-07-11 10:26:13 -07002197 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002198 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002199 PendingIntent intent, String packageName, String featureId,
2200 String listenerIdentifier) {
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -07002201 Preconditions.checkNotNull(listenerIdentifier);
2202
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002203 synchronized (mLock) {
2204 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2205 checkPackageName(packageName);
2206 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2207 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2208 request.getProvider());
2209 WorkSource workSource = request.getWorkSource();
2210 if (workSource != null && !workSource.isEmpty()) {
2211 mContext.enforceCallingOrSelfPermission(
2212 Manifest.permission.UPDATE_DEVICE_STATS, null);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002213 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002214 boolean hideFromAppOps = request.getHideFromAppOps();
2215 if (hideFromAppOps) {
2216 mContext.enforceCallingOrSelfPermission(
2217 Manifest.permission.UPDATE_APP_OPS_STATS, null);
2218 }
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002219 if (request.isLocationSettingsIgnored()) {
2220 mContext.enforceCallingOrSelfPermission(
2221 Manifest.permission.WRITE_SECURE_SETTINGS, null);
2222 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002223 boolean callerHasLocationHardwarePermission =
2224 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
2225 == PERMISSION_GRANTED;
2226 LocationRequest sanitizedRequest = createSanitizedRequest(request,
2227 allowedResolutionLevel,
2228 callerHasLocationHardwarePermission);
2229
2230 final int pid = Binder.getCallingPid();
2231 final int uid = Binder.getCallingUid();
2232
2233 long identity = Binder.clearCallingIdentity();
2234 try {
2235
2236 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
2237 // a location.
2238 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
2239
2240 if (intent == null && listener == null) {
2241 throw new IllegalArgumentException("need either listener or intent");
2242 } else if (intent != null && listener != null) {
2243 throw new IllegalArgumentException(
2244 "cannot register both listener and intent");
2245 }
2246
Hongyi Zhang700137e2019-05-23 21:19:36 -07002247 mLocationUsageLogger.logLocationApiUsage(
2248 LocationStatsEnums.USAGE_STARTED,
2249 LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
2250 packageName, request, listener != null, intent != null,
Hongyi Zhang0e9ea752019-06-09 22:49:25 -07002251 /* geofence= */ null,
Hongyi Zhang700137e2019-05-23 21:19:36 -07002252 mActivityManager.getPackageImportance(packageName));
2253
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002254 Receiver receiver;
2255 if (intent != null) {
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002256 receiver = getReceiverLocked(intent, pid, uid, packageName, featureId,
2257 workSource, hideFromAppOps, listenerIdentifier);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002258 } else {
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002259 receiver = getReceiverLocked(listener, pid, uid, packageName, featureId,
2260 workSource, hideFromAppOps, listenerIdentifier);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002261 }
2262 requestLocationUpdatesLocked(sanitizedRequest, receiver, uid, packageName);
2263 } finally {
2264 Binder.restoreCallingIdentity(identity);
2265 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002266 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002267 }
2268
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002269 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002270 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002271 int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002272 // Figure out the provider. Either its explicitly request (legacy use cases), or
2273 // use the fused provider
2274 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2275 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07002276 if (name == null) {
2277 throw new IllegalArgumentException("provider name must not be null");
2278 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07002279
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002280 LocationProvider provider = getLocationProviderLocked(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002281 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07002282 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002283 }
2284
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002285 UpdateRecord record = new UpdateRecord(name, request, receiver);
gomo48f1a642017-11-10 20:35:46 -08002286 if (D) {
2287 Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
2288 + " " + name + " " + request + " from " + packageName + "(" + uid + " "
2289 + (record.mIsForegroundUid ? "foreground" : "background")
Anil Admal08b96122019-01-30 16:55:05 -08002290 + (isThrottlingExemptLocked(receiver.mCallerIdentity)
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002291 ? " [whitelisted]" : "") + ")");
gomo48f1a642017-11-10 20:35:46 -08002292 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002293
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002294 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
2295 if (oldRecord != null) {
2296 oldRecord.disposeLocked(false);
2297 }
2298
Soonil Nagarkar397ad582019-01-23 22:47:57 -08002299 if (!provider.isUseableLocked() && !isSettingsExemptLocked(record)) {
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002300 // Notify the listener that updates are currently disabled - but only if the request
2301 // does not ignore location settings
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002302 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002303 }
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002304
2305 applyRequirementsLocked(name);
2306
David Christie0b837452013-07-29 16:02:13 -07002307 // Update the monitoring here just in case multiple location requests were added to the
2308 // same receiver (this request may be high power and the initial might not have been).
2309 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002310 }
2311
Nick Pellye0fd6932012-07-11 10:26:13 -07002312 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002313 public void removeUpdates(ILocationListener listener, PendingIntent intent,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002314 String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002315 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002316
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002317 int pid = Binder.getCallingPid();
2318 int uid = Binder.getCallingUid();
2319
2320 if (intent == null && listener == null) {
2321 throw new IllegalArgumentException("need either listener or intent");
2322 } else if (intent != null && listener != null) {
2323 throw new IllegalArgumentException("cannot register both listener and intent");
2324 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002325
Soonil Nagarkar68257742019-01-09 19:42:34 +00002326 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002327 Receiver receiver;
2328 if (intent != null) {
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002329 receiver = getReceiverLocked(intent, pid, uid, packageName, null, null, false, "");
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002330 } else {
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002331 receiver = getReceiverLocked(listener, pid, uid, packageName, null, null, false,
2332 "");
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002333 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002334
Soonil Nagarkar68257742019-01-09 19:42:34 +00002335 long identity = Binder.clearCallingIdentity();
2336 try {
2337 removeUpdatesLocked(receiver);
2338 } finally {
2339 Binder.restoreCallingIdentity(identity);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002340 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002341 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002342 }
2343
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002344 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002345 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08002346 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002347
2348 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07002349 receiver.unlinkFromListenerDeathNotificationLocked(
2350 receiver.getListener().asBinder());
Soonil Nagarkarb46c1672019-02-06 12:49:10 -08002351 receiver.clearPendingBroadcastsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002352 }
2353
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07002354 receiver.updateMonitoring(false);
2355
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002356 // Record which providers were associated with this listener
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002357 HashSet<String> providers = new HashSet<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002358 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
2359 if (oldRecords != null) {
2360 // Call dispose() on the obsolete update records.
2361 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08002362 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002363 record.disposeLocked(false);
2364 }
2365 // Accumulate providers
2366 providers.addAll(oldRecords.keySet());
2367 }
2368
2369 // update provider
2370 for (String provider : providers) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002371 applyRequirementsLocked(provider);
2372 }
2373 }
2374
Nick Pellye0fd6932012-07-11 10:26:13 -07002375 @Override
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002376 public Location getLastLocation(LocationRequest r, String packageName, String featureId) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002377 synchronized (mLock) {
2378 LocationRequest request = r != null ? r : DEFAULT_LOCATION_REQUEST;
2379 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2380 checkPackageName(packageName);
2381 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2382 request.getProvider());
2383 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07002384
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002385 final int pid = Binder.getCallingPid();
2386 final int uid = Binder.getCallingUid();
2387 final long identity = Binder.clearCallingIdentity();
2388 try {
Soonil Nagarkarb8466b72019-10-25 14:10:30 -07002389 if (mSettingsStore.isLocationPackageBlacklisted(UserHandle.getUserId(uid),
2390 packageName)) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002391 if (D) {
2392 Log.d(TAG, "not returning last loc for blacklisted app: "
2393 + packageName);
2394 }
2395 return null;
gomo48f1a642017-11-10 20:35:46 -08002396 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002397
Soonil Nagarkar68257742019-01-09 19:42:34 +00002398 // Figure out the provider. Either its explicitly request (deprecated API's),
2399 // or use the fused provider
2400 String name = request.getProvider();
2401 if (name == null) name = LocationManager.FUSED_PROVIDER;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002402 LocationProvider provider = getLocationProviderLocked(name);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002403 if (provider == null) return null;
2404
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002405 // only the current user or location providers may get location this way
Soonil Nagarkar0d77ea62019-01-31 14:36:56 -08002406 if (!isCurrentProfileLocked(UserHandle.getUserId(uid)) && !isProviderPackage(
2407 packageName)) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002408 return null;
2409 }
2410
2411 if (!provider.isUseableLocked()) {
2412 return null;
2413 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002414
2415 Location location;
2416 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2417 // Make sure that an app with coarse permissions can't get frequent location
2418 // updates by calling LocationManager.getLastKnownLocation repeatedly.
2419 location = mLastLocationCoarseInterval.get(name);
2420 } else {
2421 location = mLastLocation.get(name);
2422 }
2423 if (location == null) {
2424 return null;
2425 }
2426
2427 // Don't return stale location to apps with foreground-only location permission.
2428 String op = resolutionLevelToOpStr(allowedResolutionLevel);
Soonil Nagarkar905e7222019-10-01 12:03:29 -07002429 long locationAgeMs = TimeUnit.NANOSECONDS.toMillis(
2430 SystemClock.elapsedRealtime() - location.getElapsedRealtimeNanos());
Soonil Nagarkarb8466b72019-10-25 14:10:30 -07002431 if (locationAgeMs > mSettingsStore.getMaxLastLocationAgeMs()
Soonil Nagarkar68257742019-01-09 19:42:34 +00002432 && (mAppOps.unsafeCheckOp(op, uid, packageName)
2433 == AppOpsManager.MODE_FOREGROUND)) {
2434 return null;
2435 }
2436
Wei Wang16276a42019-02-04 18:23:31 -08002437 Location lastLocation = null;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002438 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2439 Location noGPSLocation = location.getExtraLocation(
2440 Location.EXTRA_NO_GPS_LOCATION);
2441 if (noGPSLocation != null) {
Wei Wang16276a42019-02-04 18:23:31 -08002442 lastLocation = new Location(mLocationFudger.getOrCreate(noGPSLocation));
Soonil Nagarkar68257742019-01-09 19:42:34 +00002443 }
2444 } else {
Wei Wang16276a42019-02-04 18:23:31 -08002445 lastLocation = new Location(location);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002446 }
Wei Wang16276a42019-02-04 18:23:31 -08002447 // Don't report location access if there is no last location to deliver.
2448 if (lastLocation != null) {
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002449 if (!reportLocationAccessNoThrow(pid, uid, packageName, featureId,
2450 allowedResolutionLevel, null)) {
Wei Wang16276a42019-02-04 18:23:31 -08002451 if (D) {
2452 Log.d(TAG, "not returning last loc for no op app: " + packageName);
2453 }
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07002454 lastLocation = null;
Wei Wang16276a42019-02-04 18:23:31 -08002455 }
2456 }
2457 return lastLocation;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002458 } finally {
2459 Binder.restoreCallingIdentity(identity);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002460 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002461 }
2462 }
2463
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002464 @Override
Soonil Nagarkar905e7222019-10-01 12:03:29 -07002465 public boolean getCurrentLocation(LocationRequest locationRequest,
2466 ICancellationSignal remoteCancellationSignal, ILocationListener listener,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002467 String packageName, String featureId, String listenerIdentifier) {
Soonil Nagarkar905e7222019-10-01 12:03:29 -07002468 // side effect of validating locationRequest and packageName
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002469 Location lastLocation = getLastLocation(locationRequest, packageName, featureId);
Soonil Nagarkar905e7222019-10-01 12:03:29 -07002470 if (lastLocation != null) {
2471 long locationAgeMs = TimeUnit.NANOSECONDS.toMillis(
2472 SystemClock.elapsedRealtimeNanos() - lastLocation.getElapsedRealtimeNanos());
2473
2474 long identity = Binder.clearCallingIdentity();
2475 try {
2476 if (locationAgeMs < MAX_CURRENT_LOCATION_AGE_MS) {
2477 try {
2478 listener.onLocationChanged(lastLocation);
2479 return true;
2480 } catch (RemoteException e) {
2481 Log.w(TAG, e);
2482 return false;
2483 }
2484 }
2485
2486 // packageName already validated by getLastLocation() call above
2487 boolean foreground = LocationManagerServiceUtils.isImportanceForeground(
2488 mActivityManager.getPackageImportance(packageName));
2489 if (!foreground) {
Soonil Nagarkarb8466b72019-10-25 14:10:30 -07002490 if (locationAgeMs < mSettingsStore.getBackgroundThrottleIntervalMs()) {
Soonil Nagarkar905e7222019-10-01 12:03:29 -07002491 // not allowed to request new locations, so we can't return anything
2492 return false;
2493 }
2494 }
2495 } finally {
2496 Binder.restoreCallingIdentity(identity);
2497 }
2498 }
2499
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002500 requestLocationUpdates(locationRequest, listener, null, packageName, featureId,
2501 listenerIdentifier);
Soonil Nagarkar905e7222019-10-01 12:03:29 -07002502 CancellationSignal cancellationSignal = CancellationSignal.fromTransport(
2503 remoteCancellationSignal);
2504 if (cancellationSignal != null) {
2505 cancellationSignal.setOnCancelListener(
2506 () -> removeUpdates(listener, null, packageName));
2507 }
2508 return true;
2509 }
2510
2511 @Override
Chad Brubakerf1133332019-03-15 14:13:59 -07002512 public LocationTime getGnssTimeMillis() {
2513 synchronized (mLock) {
2514 Location location = mLastLocation.get(LocationManager.GPS_PROVIDER);
2515 if (location == null) {
2516 return null;
2517 }
2518 long currentNanos = SystemClock.elapsedRealtimeNanos();
2519 long deltaMs = (currentNanos - location.getElapsedRealtimeNanos()) / 1000000L;
2520 return new LocationTime(location.getTime() + deltaMs, currentNanos);
2521 }
2522 }
2523
2524 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002525 public boolean injectLocation(Location location) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002526 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
2527 "Location Hardware permission not granted to inject location");
2528 mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
2529 "Access Fine Location permission not granted to inject Location");
2530
Soonil Nagarkar68257742019-01-09 19:42:34 +00002531 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002532 LocationProvider provider = getLocationProviderLocked(location.getProvider());
2533 if (provider == null || !provider.isUseableLocked()) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002534 return false;
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002535 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002536
2537 // NOTE: If last location is already available, location is not injected. If
2538 // provider's normal source (like a GPS chipset) have already provided an output
2539 // there is no need to inject this location.
2540 if (mLastLocation.get(provider.getName()) != null) {
2541 return false;
2542 }
2543
2544 updateLastLocationLocked(location, provider.getName());
2545 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002546 }
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002547 }
2548
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002549 @Override
2550 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002551 String packageName, String featureId, String listenerIdentifier) {
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -07002552 Preconditions.checkNotNull(listenerIdentifier);
2553
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002554 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002555 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2556 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002557 if (intent == null) {
2558 throw new IllegalArgumentException("invalid pending intent: " + null);
Victoria Lease56e675b2012-11-05 19:25:06 -08002559 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002560 checkPackageName(packageName);
2561 synchronized (mLock) {
2562 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2563 request.getProvider());
Soonil Nagarkar8c4655e2019-02-27 13:00:56 -08002564 }
2565 // Require that caller can manage given document
2566 boolean callerHasLocationHardwarePermission =
2567 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
2568 == PERMISSION_GRANTED;
2569 LocationRequest sanitizedRequest = createSanitizedRequest(request,
2570 allowedResolutionLevel,
2571 callerHasLocationHardwarePermission);
2572
2573 if (D) {
2574 Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
2575 }
2576
2577 // geo-fence manager uses the public location API, need to clear identity
2578 int uid = Binder.getCallingUid();
2579 if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
2580 // temporary measure until geofences work for secondary users
2581 Log.w(TAG, "proximity alerts are currently available only to the primary user");
2582 return;
2583 }
2584 long identity = Binder.clearCallingIdentity();
2585 try {
Hongyi Zhang700137e2019-05-23 21:19:36 -07002586 synchronized (mLock) {
2587 mLocationUsageLogger.logLocationApiUsage(
2588 LocationStatsEnums.USAGE_STARTED,
2589 LocationStatsEnums.API_REQUEST_GEOFENCE,
2590 packageName,
2591 request,
2592 /* hasListener= */ false,
2593 intent != null,
Hongyi Zhang0e9ea752019-06-09 22:49:25 -07002594 geofence,
Hongyi Zhang700137e2019-05-23 21:19:36 -07002595 mActivityManager.getPackageImportance(packageName));
2596 }
2597
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -07002598 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002599 uid, packageName, featureId, listenerIdentifier);
Soonil Nagarkar8c4655e2019-02-27 13:00:56 -08002600 } finally {
2601 Binder.restoreCallingIdentity(identity);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002602 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002603 }
2604
2605 @Override
2606 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002607 if (intent == null) {
2608 throw new IllegalArgumentException("invalid pending intent: " + null);
2609 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002610 checkPackageName(packageName);
2611
2612 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
2613
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002614 // geo-fence manager uses the public location API, need to clear identity
2615 long identity = Binder.clearCallingIdentity();
2616 try {
Hongyi Zhang700137e2019-05-23 21:19:36 -07002617 synchronized (mLock) {
2618 mLocationUsageLogger.logLocationApiUsage(
2619 LocationStatsEnums.USAGE_ENDED,
2620 LocationStatsEnums.API_REQUEST_GEOFENCE,
2621 packageName,
2622 /* LocationRequest= */ null,
2623 /* hasListener= */ false,
2624 intent != null,
Hongyi Zhang0e9ea752019-06-09 22:49:25 -07002625 geofence,
Hongyi Zhang700137e2019-05-23 21:19:36 -07002626 mActivityManager.getPackageImportance(packageName));
2627 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002628 mGeofenceManager.removeFence(geofence, intent);
2629 } finally {
2630 Binder.restoreCallingIdentity(identity);
2631 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002632 }
2633
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002634 @Override
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002635 public boolean registerGnssStatusCallback(IGnssStatusListener listener, String packageName,
2636 String featureId) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07002637 return mGnssManagerService == null ? false : mGnssManagerService.registerGnssStatusCallback(
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002638 listener, packageName, featureId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002639 }
2640
Nick Pellye0fd6932012-07-11 10:26:13 -07002641 @Override
Anil Admal98d49b72019-02-06 15:26:33 -08002642 public void unregisterGnssStatusCallback(IGnssStatusListener listener) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07002643 if (mGnssManagerService != null) mGnssManagerService.unregisterGnssStatusCallback(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002644 }
2645
Nick Pellye0fd6932012-07-11 10:26:13 -07002646 @Override
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -07002647 public boolean addGnssMeasurementsListener(IGnssMeasurementsListener listener,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002648 String packageName, String featureId, String listenerIdentifier) {
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -07002649 Preconditions.checkNotNull(listenerIdentifier);
2650
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07002651 return mGnssManagerService == null ? false
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002652 : mGnssManagerService.addGnssMeasurementsListener(listener, packageName, featureId,
2653 listenerIdentifier);
Anil Admal52686f82019-02-13 19:04:10 -08002654 }
2655
2656 @Override
2657 public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07002658 if (mGnssManagerService != null) {
2659 mGnssManagerService.removeGnssMeasurementsListener(
2660 listener);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002661 }
destradaaea8a8a62014-06-23 18:19:03 -07002662 }
2663
2664 @Override
gomo226b7b72018-12-12 16:49:39 -08002665 public void injectGnssMeasurementCorrections(
2666 GnssMeasurementCorrections measurementCorrections, String packageName) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07002667 if (mGnssManagerService != null) {
2668 mGnssManagerService.injectGnssMeasurementCorrections(
2669 measurementCorrections, packageName);
gomo226b7b72018-12-12 16:49:39 -08002670 }
2671 }
2672
2673 @Override
Anil Admal99349782019-03-19 18:58:42 -07002674 public long getGnssCapabilities(String packageName) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07002675 return mGnssManagerService == null ? 0L : mGnssManagerService.getGnssCapabilities(
2676 packageName);
gomo226b7b72018-12-12 16:49:39 -08002677 }
2678
2679 @Override
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -07002680 public boolean addGnssNavigationMessageListener(IGnssNavigationMessageListener listener,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002681 String packageName, String featureId, String listenerIdentifier) {
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -07002682 Preconditions.checkNotNull(listenerIdentifier);
2683
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07002684 return mGnssManagerService == null ? false
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -07002685 : mGnssManagerService.addGnssNavigationMessageListener(listener, packageName,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002686 featureId, listenerIdentifier);
destradaa4b3e3932014-07-21 18:01:47 -07002687 }
2688
2689 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002690 public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07002691 if (mGnssManagerService != null) {
2692 mGnssManagerService.removeGnssNavigationMessageListener(
2693 listener);
2694 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002695 }
2696
2697 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002698 public boolean sendExtraCommand(String providerName, String command, Bundle extras) {
2699 if (providerName == null) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002700 // throw NullPointerException to remain compatible with previous implementation
2701 throw new NullPointerException();
2702 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002703 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002704 checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
2705 providerName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002706
Hongyi Zhang700137e2019-05-23 21:19:36 -07002707 mLocationUsageLogger.logLocationApiUsage(
2708 LocationStatsEnums.USAGE_STARTED,
2709 LocationStatsEnums.API_SEND_EXTRA_COMMAND,
2710 providerName);
2711
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002712 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
2713 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
2714 != PERMISSION_GRANTED)) {
2715 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2716 }
2717
2718 LocationProvider provider = getLocationProviderLocked(providerName);
2719 if (provider != null) {
Soonil Nagarkard334f7b2019-07-08 16:16:19 -07002720 provider.sendExtraCommand(command, extras);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002721 }
2722
Hongyi Zhang700137e2019-05-23 21:19:36 -07002723 mLocationUsageLogger.logLocationApiUsage(
2724 LocationStatsEnums.USAGE_ENDED,
2725 LocationStatsEnums.API_SEND_EXTRA_COMMAND,
2726 providerName);
2727
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002728 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002729 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002730 }
2731
Nick Pellye0fd6932012-07-11 10:26:13 -07002732 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002733 public boolean sendNiResponse(int notifId, int userResponse) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07002734 return mGnssManagerService == null ? false : mGnssManagerService.sendNiResponse(notifId,
2735 userResponse);
Danke Xie22d1f9f2009-08-18 18:28:45 -04002736 }
2737
Nick Pellye0fd6932012-07-11 10:26:13 -07002738 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002739 public ProviderProperties getProviderProperties(String providerName) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002740 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002741 LocationProvider provider = getLocationProviderLocked(providerName);
2742 if (provider == null) {
2743 return null;
2744 }
2745 return provider.getPropertiesLocked();
2746 }
Jason Monkb71218a2015-06-17 14:44:39 -04002747 }
2748
Wei Wang980b7c22018-12-06 17:53:00 -08002749 @Override
Soonil Nagarkar0d77ea62019-01-31 14:36:56 -08002750 public boolean isProviderPackage(String packageName) {
Soonil Nagarkar514dff42019-04-30 12:04:28 -07002751 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG,
2752 Manifest.permission.READ_DEVICE_CONFIG + " permission required");
Soonil Nagarkar0d77ea62019-01-31 14:36:56 -08002753 synchronized (mLock) {
2754 for (LocationProvider provider : mProviders) {
2755 if (provider.getPackagesLocked().contains(packageName)) {
2756 return true;
2757 }
2758 }
Soonil Nagarkar0d77ea62019-01-31 14:36:56 -08002759 return false;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002760 }
Maggie2a9409e2018-03-21 11:47:28 -07002761 }
2762
Maggie2a9409e2018-03-21 11:47:28 -07002763 @Override
Wei Wang9f52d552019-10-02 14:49:02 -07002764 public List<String> getProviderPackages(String providerName) {
2765 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG,
2766 Manifest.permission.READ_DEVICE_CONFIG + " permission required");
2767 synchronized (mLock) {
2768 LocationProvider provider = getLocationProviderLocked(providerName);
2769 return provider == null ? Collections.emptyList() : provider.getPackagesLocked();
2770 }
2771 }
2772
2773 @Override
Wei Wang114922a2019-01-30 18:19:35 -08002774 public void setExtraLocationControllerPackage(String packageName) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002775 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2776 Manifest.permission.LOCATION_HARDWARE + " permission required");
Soonil Nagarkar68257742019-01-09 19:42:34 +00002777 synchronized (mLock) {
Wei Wang114922a2019-01-30 18:19:35 -08002778 mExtraLocationControllerPackage = packageName;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002779 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002780 }
2781
2782 @Override
Wei Wang114922a2019-01-30 18:19:35 -08002783 public String getExtraLocationControllerPackage() {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002784 synchronized (mLock) {
Wei Wang114922a2019-01-30 18:19:35 -08002785 return mExtraLocationControllerPackage;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002786 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002787 }
2788
2789 @Override
Wei Wang114922a2019-01-30 18:19:35 -08002790 public void setExtraLocationControllerPackageEnabled(boolean enabled) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002791 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2792 Manifest.permission.LOCATION_HARDWARE + " permission required");
Soonil Nagarkar68257742019-01-09 19:42:34 +00002793 synchronized (mLock) {
Wei Wang114922a2019-01-30 18:19:35 -08002794 mExtraLocationControllerPackageEnabled = enabled;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002795 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002796 }
2797
2798 @Override
Wei Wang114922a2019-01-30 18:19:35 -08002799 public boolean isExtraLocationControllerPackageEnabled() {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002800 synchronized (mLock) {
Wei Wang114922a2019-01-30 18:19:35 -08002801 return mExtraLocationControllerPackageEnabled
2802 && (mExtraLocationControllerPackage != null);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002803 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002804 }
2805
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002806 private boolean isLocationEnabled() {
2807 return isLocationEnabledForUser(mCurrentUserId);
2808 }
2809
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002810 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002811 public boolean isLocationEnabledForUser(int userId) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002812 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002813 if (UserHandle.getCallingUserId() != userId) {
2814 mContext.enforceCallingOrSelfPermission(
2815 Manifest.permission.INTERACT_ACROSS_USERS,
2816 "Requires INTERACT_ACROSS_USERS permission");
2817 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002818
Soonil Nagarkar68257742019-01-09 19:42:34 +00002819 long identity = Binder.clearCallingIdentity();
2820 try {
Soonil Nagarkarb8466b72019-10-25 14:10:30 -07002821 return mSettingsStore.isLocationEnabled(userId);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002822 } finally {
2823 Binder.restoreCallingIdentity(identity);
2824 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002825 }
2826
Maggie2a9409e2018-03-21 11:47:28 -07002827 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002828 public boolean isProviderEnabledForUser(String providerName, int userId) {
Maggie2a9409e2018-03-21 11:47:28 -07002829 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002830 if (UserHandle.getCallingUserId() != userId) {
2831 mContext.enforceCallingOrSelfPermission(
2832 Manifest.permission.INTERACT_ACROSS_USERS,
2833 "Requires INTERACT_ACROSS_USERS permission");
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002834 }
2835
Maggie2a9409e2018-03-21 11:47:28 -07002836 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2837 // so we discourage its use
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002838 if (FUSED_PROVIDER.equals(providerName)) return false;
Maggie2a9409e2018-03-21 11:47:28 -07002839
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002840 synchronized (mLock) {
2841 LocationProvider provider = getLocationProviderLocked(providerName);
2842 return provider != null && provider.isUseableForUserLocked(userId);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002843 }
Maggie2a9409e2018-03-21 11:47:28 -07002844 }
2845
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002846 @GuardedBy("mLock")
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002847 private static boolean shouldBroadcastSafeLocked(
Laurent Tu75defb62012-11-01 16:21:52 -07002848 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002849 // Always broadcast the first update
2850 if (lastLoc == null) {
2851 return true;
2852 }
2853
Nick Pellyf1be6862012-05-15 10:53:42 -07002854 // Check whether sufficient time has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002855 long minTime = record.mRealRequest.getFastestInterval();
Soonil Nagarkar905e7222019-10-01 12:03:29 -07002856 long deltaMs = TimeUnit.NANOSECONDS.toMillis(
2857 loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos());
2858 if (deltaMs < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002859 return false;
2860 }
2861
2862 // Check whether sufficient distance has been traveled
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002863 double minDistance = record.mRealRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002864 if (minDistance > 0.0) {
2865 if (loc.distanceTo(lastLoc) <= minDistance) {
2866 return false;
2867 }
2868 }
2869
Laurent Tu75defb62012-11-01 16:21:52 -07002870 // Check whether sufficient number of udpates is left
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002871 if (record.mRealRequest.getNumUpdates() <= 0) {
Laurent Tu75defb62012-11-01 16:21:52 -07002872 return false;
2873 }
2874
2875 // Check whether the expiry date has passed
Soonil Nagarkar95768ce2019-11-05 15:22:44 -08002876 return record.mExpirationRealtimeMs >= now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002877 }
2878
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002879 @GuardedBy("mLock")
2880 private void handleLocationChangedLocked(Location location, LocationProvider provider) {
2881 if (!mProviders.contains(provider)) {
2882 return;
2883 }
2884 if (!location.isComplete()) {
2885 Log.w(TAG, "Dropping incomplete location: " + location);
2886 return;
2887 }
2888
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002889 // only notify passive provider and update last location for locations that come from
2890 // useable providers
2891 if (provider.isUseableLocked()) {
2892 if (!provider.isPassiveLocked()) {
2893 mPassiveProvider.updateLocation(location);
2894 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002895 }
2896
Soonil Nagarkar68257742019-01-09 19:42:34 +00002897 if (D) Log.d(TAG, "incoming location: " + location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002898 long now = SystemClock.elapsedRealtime();
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002899 if (provider.isUseableLocked()) {
2900 updateLastLocationLocked(location, provider.getName());
Mike Lockwood4e50b782009-04-03 08:24:43 -07002901 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002902
David Christie1b9b7b12013-04-15 15:31:11 -07002903 // Update last known coarse interval location if enough time has passed.
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002904 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(
2905 provider.getName());
David Christie1b9b7b12013-04-15 15:31:11 -07002906 if (lastLocationCoarseInterval == null) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002907 lastLocationCoarseInterval = new Location(location);
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002908
2909 if (provider.isUseableLocked()) {
2910 mLastLocationCoarseInterval.put(provider.getName(), lastLocationCoarseInterval);
2911 }
David Christie1b9b7b12013-04-15 15:31:11 -07002912 }
Soonil Nagarkar905e7222019-10-01 12:03:29 -07002913 long timeDeltaMs = TimeUnit.NANOSECONDS.toMillis(location.getElapsedRealtimeNanos()
2914 - lastLocationCoarseInterval.getElapsedRealtimeNanos());
2915 if (timeDeltaMs > LocationFudger.FASTEST_INTERVAL_MS) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002916 lastLocationCoarseInterval.set(location);
David Christie1b9b7b12013-04-15 15:31:11 -07002917 }
2918 // Don't ever return a coarse location that is more recent than the allowed update
2919 // interval (i.e. don't allow an app to keep registering and unregistering for
2920 // location updates to overcome the minimum interval).
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002921 Location noGPSLocation =
David Christie1b9b7b12013-04-15 15:31:11 -07002922 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2923
Laurent Tu60ec50a2012-10-04 17:00:10 -07002924 // Skip if there are no UpdateRecords for this provider.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002925 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
Laurent Tu60ec50a2012-10-04 17:00:10 -07002926 if (records == null || records.size() == 0) return;
2927
Victoria Lease09016ab2012-09-16 12:33:15 -07002928 // Fetch coarse location
2929 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07002930 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002931 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2932 }
2933
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002934 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002935 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07002936
Soonil Nagarkar94749f72018-11-08 11:46:43 -08002937 // Broadcast location to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002938 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002939 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07002940 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07002941
Soonil Nagarkar397ad582019-01-23 22:47:57 -08002942 if (!provider.isUseableLocked() && !isSettingsExemptLocked(r)) {
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002943 continue;
2944 }
2945
Anil Admal08b96122019-01-30 16:55:05 -08002946 int receiverUserId = UserHandle.getUserId(receiver.mCallerIdentity.mUid);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002947 if (!isCurrentProfileLocked(receiverUserId)
Soonil Nagarkar0d77ea62019-01-31 14:36:56 -08002948 && !isProviderPackage(receiver.mCallerIdentity.mPackageName)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07002949 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07002950 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07002951 " (current user: " + mCurrentUserId + ", app: " +
Anil Admal08b96122019-01-30 16:55:05 -08002952 receiver.mCallerIdentity.mPackageName + ")");
Victoria Leaseb711d572012-10-02 13:14:11 -07002953 }
2954 continue;
2955 }
2956
Soonil Nagarkarb8466b72019-10-25 14:10:30 -07002957 if (mSettingsStore.isLocationPackageBlacklisted(receiverUserId,
2958 receiver.mCallerIdentity.mPackageName)) {
gomo48f1a642017-11-10 20:35:46 -08002959 if (D) {
2960 Log.d(TAG, "skipping loc update for blacklisted app: " +
Anil Admal08b96122019-01-30 16:55:05 -08002961 receiver.mCallerIdentity.mPackageName);
gomo48f1a642017-11-10 20:35:46 -08002962 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002963 continue;
2964 }
2965
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002966 Location notifyLocation;
Victoria Lease37425c32012-10-16 16:08:48 -07002967 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2968 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002969 } else {
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002970 notifyLocation = location; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002971 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002972 if (notifyLocation != null) {
2973 Location lastLoc = r.mLastFixBroadcast;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002974 if ((lastLoc == null)
2975 || shouldBroadcastSafeLocked(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002976 if (lastLoc == null) {
2977 lastLoc = new Location(notifyLocation);
2978 r.mLastFixBroadcast = lastLoc;
2979 } else {
2980 lastLoc.set(notifyLocation);
2981 }
Wei Wang8486fc72019-03-07 18:49:21 -08002982 // Report location access before delivering location to the client. This will
2983 // note location delivery to appOps, so it should be called only when a
2984 // location is really being delivered to the client.
2985 if (!reportLocationAccessNoThrow(
2986 receiver.mCallerIdentity.mPid,
2987 receiver.mCallerIdentity.mUid,
2988 receiver.mCallerIdentity.mPackageName,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -07002989 receiver.mCallerIdentity.mFeatureId,
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -07002990 receiver.mAllowedResolutionLevel,
2991 "Location sent to " + receiver.mCallerIdentity.mListenerIdentifier)) {
Wei Wang8486fc72019-03-07 18:49:21 -08002992 if (D) {
2993 Log.d(TAG, "skipping loc update for no op app: "
2994 + receiver.mCallerIdentity.mPackageName);
2995 }
2996 continue;
2997 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002998 if (!receiver.callLocationChangedLocked(notifyLocation)) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002999 Slog.w(TAG, "RemoteException calling onLocationChanged on "
3000 + receiver);
Victoria Lease09016ab2012-09-16 12:33:15 -07003001 receiverDead = true;
3002 }
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003003 r.mRealRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003004 }
3005 }
3006
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003007 // track expired records
Soonil Nagarkar95768ce2019-11-05 15:22:44 -08003008 if (r.mRealRequest.getNumUpdates() <= 0 || r.mExpirationRealtimeMs < now) {
Soonil Nagarkar39d614a2019-10-31 12:10:31 -07003009 // notify the client it can remove this listener
3010 r.mReceiver.callRemovedLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003011 if (deadUpdateRecords == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003012 deadUpdateRecords = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003013 }
3014 deadUpdateRecords.add(r);
3015 }
3016 // track dead receivers
3017 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07003018 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003019 deadReceivers = new ArrayList<>();
Mike Lockwood03ca2162010-04-01 08:10:09 -07003020 }
3021 if (!deadReceivers.contains(receiver)) {
3022 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003023 }
3024 }
3025 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003026
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003027 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003028 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003029 for (Receiver receiver : deadReceivers) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003030 removeUpdatesLocked(receiver);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003031 }
3032 }
3033 if (deadUpdateRecords != null) {
3034 for (UpdateRecord r : deadUpdateRecords) {
3035 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003036 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003037 applyRequirementsLocked(provider);
Victoria Lease8b38b292012-12-04 15:04:43 -08003038 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003039 }
3040
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003041 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00003042 private void updateLastLocationLocked(Location location, String provider) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003043 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3044 Location lastNoGPSLocation;
3045 Location lastLocation = mLastLocation.get(provider);
3046 if (lastLocation == null) {
3047 lastLocation = new Location(provider);
3048 mLastLocation.put(provider, lastLocation);
3049 } else {
3050 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3051 if (noGPSLocation == null && lastNoGPSLocation != null) {
3052 // New location has no no-GPS location: adopt last no-GPS location. This is set
3053 // directly into location because we do not want to notify COARSE clients.
3054 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
3055 }
3056 }
3057 lastLocation.set(location);
3058 }
3059
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003060 // Geocoder
3061
Nick Pellye0fd6932012-07-11 10:26:13 -07003062 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04003063 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07003064 return mGeocodeProvider != null;
3065 }
3066
Nick Pellye0fd6932012-07-11 10:26:13 -07003067 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003068 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003069 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003070 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003071 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
3072 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003073 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003074 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003075 }
3076
Mike Lockwooda55c3212009-04-15 11:10:11 -04003077
Nick Pellye0fd6932012-07-11 10:26:13 -07003078 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003079 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04003080 double lowerLeftLatitude, double lowerLeftLongitude,
3081 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003082 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003083
3084 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003085 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
3086 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
3087 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003088 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003089 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003090 }
3091
3092 // Mock Providers
3093
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003094 private boolean canCallerAccessMockLocation(String opPackageName) {
Wei Wang16276a42019-02-04 18:23:31 -08003095 return mAppOps.checkOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003096 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003097 }
3098
Nick Pellye0fd6932012-07-11 10:26:13 -07003099 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00003100 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003101 if (!canCallerAccessMockLocation(opPackageName)) {
3102 return;
3103 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003104
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003105 if (PASSIVE_PROVIDER.equals(name)) {
Mike Lockwooda4903f22010-02-17 06:42:23 -05003106 throw new IllegalArgumentException("Cannot mock the passive location provider");
3107 }
3108
Soonil Nagarkar68257742019-01-09 19:42:34 +00003109 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003110 long identity = Binder.clearCallingIdentity();
3111 try {
3112 LocationProvider oldProvider = getLocationProviderLocked(name);
3113 if (oldProvider != null) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003114 removeProviderLocked(oldProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003115 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003116
3117 MockLocationProvider mockProviderManager = new MockLocationProvider(name);
3118 addProviderLocked(mockProviderManager);
Soonil Nagarkar0d77ea62019-01-31 14:36:56 -08003119 mockProviderManager.attachLocked(
3120 new MockProvider(mContext, mockProviderManager, properties));
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003121 } finally {
3122 Binder.restoreCallingIdentity(identity);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003123 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003124 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003125 }
3126
Nick Pellye0fd6932012-07-11 10:26:13 -07003127 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003128 public void removeTestProvider(String name, String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003129 if (!canCallerAccessMockLocation(opPackageName)) {
3130 return;
3131 }
3132
Soonil Nagarkar68257742019-01-09 19:42:34 +00003133 synchronized (mLock) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003134 long identity = Binder.clearCallingIdentity();
3135 try {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003136 LocationProvider testProvider = getLocationProviderLocked(name);
3137 if (testProvider == null || !testProvider.isMock()) {
Soonil Nagarkar0000e8a2019-10-08 14:32:07 -07003138 return;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003139 }
3140
3141 removeProviderLocked(testProvider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003142
Soonil Nagarkar68257742019-01-09 19:42:34 +00003143 // reinstate real provider if available
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003144 LocationProvider realProvider = null;
3145 for (LocationProvider provider : mRealProviders) {
3146 if (name.equals(provider.getName())) {
3147 realProvider = provider;
3148 break;
3149 }
3150 }
3151
Soonil Nagarkar68257742019-01-09 19:42:34 +00003152 if (realProvider != null) {
3153 addProviderLocked(realProvider);
3154 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003155 } finally {
3156 Binder.restoreCallingIdentity(identity);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003157 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003158 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003159 }
3160
Nick Pellye0fd6932012-07-11 10:26:13 -07003161 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003162 public void setTestProviderLocation(String providerName, Location location,
Soonil Nagarkar68257742019-01-09 19:42:34 +00003163 String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003164 if (!canCallerAccessMockLocation(opPackageName)) {
3165 return;
3166 }
3167
Soonil Nagarkar68257742019-01-09 19:42:34 +00003168 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003169 LocationProvider testProvider = getLocationProviderLocked(providerName);
3170 if (testProvider == null || !testProvider.isMock()) {
3171 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003172 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003173
3174 String locationProvider = location.getProvider();
3175 if (!TextUtils.isEmpty(locationProvider) && !providerName.equals(locationProvider)) {
3176 // The location has an explicit provider that is different from the mock
3177 // provider name. The caller may be trying to fool us via b/33091107.
3178 EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
3179 providerName + "!=" + location.getProvider());
3180 }
3181
3182 ((MockLocationProvider) testProvider).setLocationLocked(location);
Soonil Nagarkar68257742019-01-09 19:42:34 +00003183 }
3184 }
3185
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003186 @Override
3187 public void setTestProviderEnabled(String providerName, boolean enabled, String opPackageName) {
3188 if (!canCallerAccessMockLocation(opPackageName)) {
3189 return;
3190 }
3191
3192 synchronized (mLock) {
3193 LocationProvider testProvider = getLocationProviderLocked(providerName);
3194 if (testProvider == null || !testProvider.isMock()) {
3195 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
3196 }
3197
3198 ((MockLocationProvider) testProvider).setEnabledLocked(enabled);
3199 }
3200 }
3201
3202 @Override
Kweku Adams4fb074e2019-02-01 16:03:27 -08003203 @NonNull
3204 public List<LocationRequest> getTestProviderCurrentRequests(String providerName,
3205 String opPackageName) {
3206 if (!canCallerAccessMockLocation(opPackageName)) {
3207 return Collections.emptyList();
3208 }
3209
3210 synchronized (mLock) {
3211 LocationProvider testProvider = getLocationProviderLocked(providerName);
3212 if (testProvider == null || !testProvider.isMock()) {
3213 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
3214 }
3215
3216 MockLocationProvider provider = (MockLocationProvider) testProvider;
3217 if (provider.mCurrentRequest == null) {
3218 return Collections.emptyList();
3219 }
3220 List<LocationRequest> requests = new ArrayList<>();
3221 for (LocationRequest request : provider.mCurrentRequest.locationRequests) {
3222 requests.add(new LocationRequest(request));
3223 }
3224 return requests;
3225 }
3226 }
3227
3228 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003229 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06003230 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Nick Pellye0fd6932012-07-11 10:26:13 -07003231
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003232 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
3233
Soonil Nagarkar68257742019-01-09 19:42:34 +00003234 synchronized (mLock) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07003235 if (mGnssManagerService != null && args.length > 0 && args[0].equals("--gnssmetrics")) {
3236 mGnssManagerService.dump(fd, pw, args);
Siddharth Raybb608c82017-03-16 11:33:34 -07003237 }
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003238
3239 ipw.println("Location Manager State:");
3240 ipw.increaseIndent();
3241 ipw.print("Current System Time: "
WyattRileyba6072f2019-04-18 07:37:52 -07003242 + TimeUtils.logTimeOfDay(System.currentTimeMillis()));
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003243 ipw.println(", Current Elapsed Time: "
WyattRileyba6072f2019-04-18 07:37:52 -07003244 + TimeUtils.formatDuration(SystemClock.elapsedRealtime()));
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003245 ipw.println("Current user: " + mCurrentUserId + " " + Arrays.toString(
Soonil Nagarkarb46c1672019-02-06 12:49:10 -08003246 mCurrentUserProfiles));
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003247 ipw.println("Location Mode: " + isLocationEnabled());
3248 ipw.println("Battery Saver Location Mode: "
Kweku Adams4fb074e2019-02-01 16:03:27 -08003249 + locationPowerSaveModeToString(mBatterySaverMode));
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003250
3251 ipw.println("Location Listeners:");
3252 ipw.increaseIndent();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003253 for (Receiver receiver : mReceivers.values()) {
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003254 ipw.println(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003255 }
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003256 ipw.decreaseIndent();
3257
3258 ipw.println("Active Records by Provider:");
3259 ipw.increaseIndent();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003260 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003261 ipw.println(entry.getKey() + ":");
3262 ipw.increaseIndent();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003263 for (UpdateRecord record : entry.getValue()) {
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003264 ipw.println(record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003265 }
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003266 ipw.decreaseIndent();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003267 }
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003268 ipw.decreaseIndent();
Anil Admal98d49b72019-02-06 15:26:33 -08003269
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003270 ipw.println("Historical Records by Provider:");
3271 ipw.increaseIndent();
David Christie2ff96af2014-01-30 16:09:37 -08003272 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
3273 : mRequestStatistics.statistics.entrySet()) {
3274 PackageProviderKey key = entry.getKey();
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003275 ipw.println(key.packageName + ": " + key.providerName + ": " + entry.getValue());
David Christie2ff96af2014-01-30 16:09:37 -08003276 }
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003277 ipw.decreaseIndent();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003278
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003279 ipw.println("Last Known Locations:");
3280 ipw.increaseIndent();
3281 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
3282 ipw.println(entry.getKey() + ": " + entry.getValue());
David Christie1b9b7b12013-04-15 15:31:11 -07003283 }
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003284 ipw.decreaseIndent();
3285
3286 ipw.println("Last Known Coarse Locations:");
3287 ipw.increaseIndent();
3288 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
3289 ipw.println(entry.getKey() + ": " + entry.getValue());
3290 }
3291 ipw.decreaseIndent();
David Christie1b9b7b12013-04-15 15:31:11 -07003292
Tyler Trephan2f3ee9a2019-03-21 10:54:22 -07003293 if (mGeofenceManager != null) {
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003294 ipw.println("Geofences:");
3295 ipw.increaseIndent();
3296 mGeofenceManager.dump(ipw);
3297 ipw.decreaseIndent();
Tyler Trephan2f3ee9a2019-03-21 10:54:22 -07003298 }
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07003299
Wei Wang114922a2019-01-30 18:19:35 -08003300 if (mExtraLocationControllerPackage != null) {
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003301 ipw.println("Location Controller Extra Package: " + mExtraLocationControllerPackage
3302 + (mExtraLocationControllerPackageEnabled ? " [enabled]" : "[disabled]"));
Wei Wang980b7c22018-12-06 17:53:00 -08003303 }
3304
Tyler Trephan2f3ee9a2019-03-21 10:54:22 -07003305 if (mLocationFudger != null) {
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003306 ipw.println("Location Fudger:");
3307 ipw.increaseIndent();
3308 mLocationFudger.dump(fd, ipw, args);
3309 ipw.decreaseIndent();
Tyler Trephan2f3ee9a2019-03-21 10:54:22 -07003310 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003311
Soonil Nagarkar1249eaf2019-11-21 12:40:49 -08003312 ipw.println("Location Settings:");
3313 ipw.increaseIndent();
3314 mSettingsStore.dump(fd, ipw, args);
3315 ipw.decreaseIndent();
Soonil Nagarkarb8466b72019-10-25 14:10:30 -07003316
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003317 ipw.println("Location Providers:");
3318 ipw.increaseIndent();
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003319 for (LocationProvider provider : mProviders) {
Soonil Nagarkar1c572552019-07-10 13:31:47 -07003320 provider.dumpLocked(fd, ipw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003321 }
Soonil Nagarkar1249eaf2019-11-21 12:40:49 -08003322 ipw.decreaseIndent();
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07003323 }
Anil Admal98d49b72019-02-06 15:26:33 -08003324
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07003325 if (mGnssManagerService != null) {
Soonil Nagarkar1249eaf2019-11-21 12:40:49 -08003326 ipw.println("GNSS:");
3327 ipw.increaseIndent();
3328 mGnssManagerService.dump(fd, ipw, args);
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07003329 ipw.decreaseIndent();
Anil Admal98d49b72019-02-06 15:26:33 -08003330 }
3331 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003332}