blob: 64ca2e3eb3de871b6f1edaf5c15fdd5ac90eebe7 [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
Svet Ganovadc1cf42015-06-15 16:36:24 -070019import android.content.pm.PackageManagerInternal;
destradaaea8a8a62014-06-23 18:19:03 -070020import com.android.internal.content.PackageMonitor;
21import com.android.internal.location.ProviderProperties;
22import com.android.internal.location.ProviderRequest;
23import com.android.internal.os.BackgroundThread;
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -070024import com.android.internal.util.ArrayUtils;
destradaaa4fa3b52014-07-09 10:46:39 -070025import com.android.server.location.ActivityRecognitionProxy;
destradaaea8a8a62014-06-23 18:19:03 -070026import com.android.server.location.FlpHardwareProvider;
27import com.android.server.location.FusedProxy;
28import com.android.server.location.GeocoderProxy;
29import com.android.server.location.GeofenceManager;
30import com.android.server.location.GeofenceProxy;
Lifu Tang818aa2c2016-02-01 01:52:00 -080031import com.android.server.location.GnssLocationProvider;
32import com.android.server.location.GnssMeasurementsProvider;
33import com.android.server.location.GnssNavigationMessageProvider;
destradaaea8a8a62014-06-23 18:19:03 -070034import com.android.server.location.LocationBlacklist;
35import com.android.server.location.LocationFudger;
36import com.android.server.location.LocationProviderInterface;
37import com.android.server.location.LocationProviderProxy;
38import com.android.server.location.LocationRequestStatistics;
39import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
40import com.android.server.location.LocationRequestStatistics.PackageStatistics;
41import com.android.server.location.MockProvider;
42import com.android.server.location.PassiveProvider;
43
Dianne Hackborna06de0f2012-12-11 16:34:47 -080044import android.app.AppOpsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.app.PendingIntent;
Victoria Lease38389b62012-09-30 11:44:22 -070046import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.content.ContentResolver;
48import android.content.Context;
49import android.content.Intent;
Victoria Lease38389b62012-09-30 11:44:22 -070050import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070051import android.content.pm.ApplicationInfo;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050052import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.content.pm.PackageManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070054import android.content.pm.PackageManager.NameNotFoundException;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050055import android.content.pm.ResolveInfo;
56import android.content.pm.Signature;
Mike Lockwood628fd6d2010-01-25 22:46:13 -050057import android.content.res.Resources;
Brian Muramatsubb95cb92012-08-29 10:43:21 -070058import android.database.ContentObserver;
destradaaa4fa3b52014-07-09 10:46:39 -070059import android.hardware.location.ActivityRecognitionHardware;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070061import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050062import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070063import android.location.Geofence;
Lifu Tang818aa2c2016-02-01 01:52:00 -080064import android.location.IGnssMeasurementsListener;
Lifu Tang30f95a72016-01-07 23:20:38 -080065import android.location.IGnssStatusListener;
66import android.location.IGnssStatusProvider;
Wei Liu5241a4c2015-05-11 14:00:36 -070067import android.location.IGpsGeofenceHardware;
Lifu Tang818aa2c2016-02-01 01:52:00 -080068import android.location.IGnssNavigationMessageListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069import android.location.ILocationListener;
70import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040071import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.location.Location;
73import android.location.LocationManager;
74import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070075import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076import android.os.Binder;
77import android.os.Bundle;
78import android.os.Handler;
79import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070080import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081import android.os.Message;
82import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070083import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070085import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070086import android.os.UserHandle;
Amith Yamasanib27528d2014-06-05 15:02:10 -070087import android.os.UserManager;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070088import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080091import android.util.Slog;
Amith Yamasanib27528d2014-06-05 15:02:10 -070092
Mike Lockwood43e33f22010-03-26 10:41:48 -040093import java.io.FileDescriptor;
94import java.io.PrintWriter;
95import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070096import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040097import java.util.HashMap;
98import java.util.HashSet;
99import java.util.List;
100import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400101import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102
103/**
104 * The service class that manages LocationProviders and issues location
105 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 */
Victoria Lease5cd731a2012-12-19 15:04:21 -0800107public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -0800109 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700110
111 private static final String WAKELOCK_KEY = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112
Victoria Lease37425c32012-10-16 16:08:48 -0700113 // Location resolution level: no location data whatsoever
114 private static final int RESOLUTION_LEVEL_NONE = 0;
115 // Location resolution level: coarse location data only
116 private static final int RESOLUTION_LEVEL_COARSE = 1;
117 // Location resolution level: fine location data
118 private static final int RESOLUTION_LEVEL_FINE = 2;
119
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700121 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700123 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400124 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700125 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
126
127 private static final String NETWORK_LOCATION_SERVICE_ACTION =
Stan Chesnutt39062dd2013-07-22 14:33:30 -0700128 "com.android.location.service.v3.NetworkLocationProvider";
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700129 private static final String FUSED_LOCATION_SERVICE_ACTION =
130 "com.android.location.service.FusedLocationProvider";
131
132 private static final int MSG_LOCATION_CHANGED = 1;
133
David Christie1b9b7b12013-04-15 15:31:11 -0700134 private static final long NANOS_PER_MILLI = 1000000L;
135
David Christie0b837452013-07-29 16:02:13 -0700136 // The maximum interval a location request can have and still be considered "high power".
137 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
138
Nick Pellyf1be6862012-05-15 10:53:42 -0700139 // Location Providers may sometimes deliver location updates
140 // slightly faster that requested - provide grace period so
141 // we don't unnecessarily filter events that are otherwise on
142 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700143 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700144
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700145 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
146
147 private final Context mContext;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800148 private final AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700149
150 // used internally for synchronization
151 private final Object mLock = new Object();
152
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700153 // --- fields below are final after systemRunning() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700154 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700155 private GeofenceManager mGeofenceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700156 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700157 private PowerManager mPowerManager;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700158 private UserManager mUserManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700159 private GeocoderProxy mGeocodeProvider;
Lifu Tang30f95a72016-01-07 23:20:38 -0800160 private IGnssStatusProvider mGnssStatusProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700161 private INetInitiatedListener mNetInitiatedListener;
162 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700163 private PassiveProvider mPassiveProvider; // track passive provider for special cases
164 private LocationBlacklist mBlacklist;
Lifu Tang818aa2c2016-02-01 01:52:00 -0800165 private GnssMeasurementsProvider mGnssMeasurementsProvider;
166 private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
Wei Liu5241a4c2015-05-11 14:00:36 -0700167 private IGpsGeofenceHardware mGpsGeofenceProxy;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700168
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 // Set of providers that are explicitly enabled
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700171 // Only used by passive, fused & test. Network & GPS are controlled separately, and not listed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 private final Set<String> mEnabledProviders = new HashSet<String>();
173
174 // Set of providers that are explicitly disabled
175 private final Set<String> mDisabledProviders = new HashSet<String>();
176
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700177 // Mock (test) providers
178 private final HashMap<String, MockProvider> mMockProviders =
179 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700181 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400182 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700184 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500185 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700186 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400187
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700188 // real providers, saved here when mocked out
189 private final HashMap<String, LocationProviderInterface> mRealProviders =
190 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700192 // mapping from provider name to provider
193 private final HashMap<String, LocationProviderInterface> mProvidersByName =
194 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700196 // mapping from provider name to all its UpdateRecords
197 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
198 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700199
David Christie2ff96af2014-01-30 16:09:37 -0800200 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
201
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700202 // mapping from provider name to last known location
203 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204
David Christie1b9b7b12013-04-15 15:31:11 -0700205 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
206 // locations stored here are not fudged for coarse permissions.
207 private final HashMap<String, Location> mLastLocationCoarseInterval =
208 new HashMap<String, Location>();
209
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700210 // all providers that operate over proxy, for authorizing incoming location
211 private final ArrayList<LocationProviderProxy> mProxyProviders =
212 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213
Victoria Lease38389b62012-09-30 11:44:22 -0700214 // current active user on the device - other users are denied location data
Xiaohui Chena4490622015-09-22 15:29:31 -0700215 private int mCurrentUserId = UserHandle.USER_SYSTEM;
216 private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_SYSTEM };
Victoria Lease38389b62012-09-30 11:44:22 -0700217
Lifu Tang9363b942016-02-16 18:07:00 -0800218 private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
Lifu Tang82f893d2016-01-21 18:15:33 -0800219
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700220 public LocationManagerService(Context context) {
221 super();
222 mContext = context;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800223 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800224
Svet Ganovadc1cf42015-06-15 16:36:24 -0700225 // Let the package manager query which are the default location
226 // providers as they get certain permissions granted by default.
227 PackageManagerInternal packageManagerInternal = LocalServices.getService(
228 PackageManagerInternal.class);
229 packageManagerInternal.setLocationPackagesProvider(
230 new PackageManagerInternal.PackagesProvider() {
231 @Override
232 public String[] getPackages(int userId) {
233 return mContext.getResources().getStringArray(
234 com.android.internal.R.array.config_locationProviderPackageNames);
235 }
236 });
237
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700238 if (D) Log.d(TAG, "Constructed");
239
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700240 // most startup is deferred until systemRunning()
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700241 }
242
Svetoslav Ganova0027152013-06-25 14:59:53 -0700243 public void systemRunning() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700244 synchronized (mLock) {
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700245 if (D) Log.d(TAG, "systemRunning()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700246
Victoria Lease5cd731a2012-12-19 15:04:21 -0800247 // fetch package manager
248 mPackageManager = mContext.getPackageManager();
249
Victoria Lease0aa28602013-05-29 15:28:26 -0700250 // fetch power manager
251 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800252
253 // prepare worker thread
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700254 mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
Victoria Lease5cd731a2012-12-19 15:04:21 -0800255
256 // prepare mLocationHandler's dependents
257 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
258 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
259 mBlacklist.init();
260 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
261
Dianne Hackbornc2293022013-02-06 23:14:49 -0800262 // Monitor for app ops mode changes.
Dianne Hackborn9bb0ee92013-09-22 12:31:38 -0700263 AppOpsManager.OnOpChangedListener callback
264 = new AppOpsManager.OnOpChangedInternalListener() {
265 public void onOpChanged(int op, String packageName) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800266 synchronized (mLock) {
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700267 for (Receiver receiver : mReceivers.values()) {
268 receiver.updateMonitoring(true);
269 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800270 applyAllProviderRequirementsLocked();
271 }
272 }
273 };
274 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
275
David Christieb870dbf2015-06-22 12:42:53 -0700276 PackageManager.OnPermissionsChangedListener permissionListener
277 = new PackageManager.OnPermissionsChangedListener() {
278 @Override
279 public void onPermissionsChanged(final int uid) {
280 synchronized (mLock) {
281 applyAllProviderRequirementsLocked();
282 }
283 }
284 };
285 mPackageManager.addOnPermissionsChangeListener(permissionListener);
286
Amith Yamasanib27528d2014-06-05 15:02:10 -0700287 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
288 updateUserProfiles(mCurrentUserId);
289
Victoria Lease5cd731a2012-12-19 15:04:21 -0800290 // prepare providers
291 loadProvidersLocked();
292 updateProvidersLocked();
293 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700294
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700295 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700296 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700297 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700298 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800299 @Override
300 public void onChange(boolean selfChange) {
301 synchronized (mLock) {
302 updateProvidersLocked();
303 }
304 }
305 }, UserHandle.USER_ALL);
306 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700307
Victoria Lease38389b62012-09-30 11:44:22 -0700308 // listen for user change
309 IntentFilter intentFilter = new IntentFilter();
310 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700311 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
312 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
destradaab9026982015-08-27 17:34:54 -0700313 intentFilter.addAction(Intent.ACTION_SHUTDOWN);
Victoria Lease38389b62012-09-30 11:44:22 -0700314
315 mContext.registerReceiverAsUser(new BroadcastReceiver() {
316 @Override
317 public void onReceive(Context context, Intent intent) {
318 String action = intent.getAction();
319 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
320 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
Amith Yamasanib27528d2014-06-05 15:02:10 -0700321 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
322 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
323 updateUserProfiles(mCurrentUserId);
destradaab9026982015-08-27 17:34:54 -0700324 } else if (Intent.ACTION_SHUTDOWN.equals(action)) {
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700325 // shutdown only if UserId indicates whole system, not just one user
326 if(D) Log.d(TAG, "Shutdown received with UserId: " + getSendingUserId());
327 if (getSendingUserId() == UserHandle.USER_ALL) {
328 shutdownComponents();
329 }
Victoria Lease38389b62012-09-30 11:44:22 -0700330 }
331 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800332 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700333 }
334
Amith Yamasanib27528d2014-06-05 15:02:10 -0700335 /**
destradaab9026982015-08-27 17:34:54 -0700336 * Provides a way for components held by the {@link LocationManagerService} to clean-up
337 * gracefully on system's shutdown.
338 *
339 * NOTES:
340 * 1) Only provides a chance to clean-up on an opt-in basis. This guarantees back-compat
341 * support for components that do not wish to handle such event.
342 */
343 private void shutdownComponents() {
344 if(D) Log.d(TAG, "Shutting down components...");
345
346 LocationProviderInterface gpsProvider = mProvidersByName.get(LocationManager.GPS_PROVIDER);
347 if (gpsProvider != null && gpsProvider.isEnabled()) {
348 gpsProvider.disable();
349 }
350
destradaa2e385072015-10-14 16:45:58 -0700351 // it is needed to check if FLP HW provider is supported before accessing the instance, this
352 // avoids an exception to be thrown by the singleton factory method
353 if (FlpHardwareProvider.isSupported()) {
354 FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
destradaab9026982015-08-27 17:34:54 -0700355 flpHardwareProvider.cleanup();
356 }
357 }
358
359 /**
Amith Yamasanib27528d2014-06-05 15:02:10 -0700360 * Makes a list of userids that are related to the current user. This is
361 * relevant when using managed profiles. Otherwise the list only contains
362 * the current user.
363 *
364 * @param currentUserId the current user, who might have an alter-ego.
365 */
366 void updateUserProfiles(int currentUserId) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700367 int[] profileIds = mUserManager.getProfileIdsWithDisabled(currentUserId);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700368 synchronized (mLock) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700369 mCurrentUserProfiles = profileIds;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700370 }
371 }
372
373 /**
374 * Checks if the specified userId matches any of the current foreground
375 * users stored in mCurrentUserProfiles.
376 */
377 private boolean isCurrentProfile(int userId) {
378 synchronized (mLock) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700379 return ArrayUtils.contains(mCurrentUserProfiles, userId);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700380 }
381 }
382
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500383 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
384 PackageManager pm = mContext.getPackageManager();
385 String systemPackageName = mContext.getPackageName();
386 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
387
388 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
389 new Intent(FUSED_LOCATION_SERVICE_ACTION),
390 PackageManager.GET_META_DATA, mCurrentUserId);
391 for (ResolveInfo rInfo : rInfos) {
392 String packageName = rInfo.serviceInfo.packageName;
393
394 // Check that the signature is in the list of supported sigs. If it's not in
395 // this list the standard provider binding logic won't bind to it.
396 try {
397 PackageInfo pInfo;
398 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
399 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
400 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
401 ", but has wrong signature, ignoring");
402 continue;
403 }
404 } catch (NameNotFoundException e) {
405 Log.e(TAG, "missing package: " + packageName);
406 continue;
407 }
408
409 // Get the version info
410 if (rInfo.serviceInfo.metaData == null) {
411 Log.w(TAG, "Found fused provider without metadata: " + packageName);
412 continue;
413 }
414
415 int version = rInfo.serviceInfo.metaData.getInt(
416 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
417 if (version == 0) {
418 // This should be the fallback fused location provider.
419
420 // Make sure it's in the system partition.
421 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
422 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
423 continue;
424 }
425
426 // Check that the fallback is signed the same as the OS
427 // as a proxy for coreApp="true"
428 if (pm.checkSignatures(systemPackageName, packageName)
429 != PackageManager.SIGNATURE_MATCH) {
430 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
431 + packageName);
432 continue;
433 }
434
435 // Found a valid fallback.
436 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
437 return;
438 } else {
439 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
440 }
441 }
442
443 throw new IllegalStateException("Unable to find a fused location provider that is in the "
444 + "system partition with version 0 and signed with the platform certificate. "
445 + "Such a package is needed to provide a default fused location provider in the "
446 + "event that no other fused location provider has been installed or is currently "
447 + "available. For example, coreOnly boot mode when decrypting the data "
448 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
449 }
450
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700451 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700452 // create a passive location provider, which is always enabled
453 PassiveProvider passiveProvider = new PassiveProvider(this);
454 addProviderLocked(passiveProvider);
455 mEnabledProviders.add(passiveProvider.getName());
456 mPassiveProvider = passiveProvider;
457
Lifu Tang30f95a72016-01-07 23:20:38 -0800458 if (GnssLocationProvider.isSupported()) {
Wei Liu5241a4c2015-05-11 14:00:36 -0700459 // Create a gps location provider
Lifu Tang30f95a72016-01-07 23:20:38 -0800460 GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext, this,
Wei Liu5241a4c2015-05-11 14:00:36 -0700461 mLocationHandler.getLooper());
Lifu Tang9363b942016-02-16 18:07:00 -0800462 mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800463 mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
464 mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
465 addProviderLocked(gnssProvider);
466 mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProvider);
Lifu Tang818aa2c2016-02-01 01:52:00 -0800467 mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
468 mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800469 mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700470 }
471
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700472 /*
473 Load package name(s) containing location provider support.
474 These packages can contain services implementing location providers:
475 Geocoder Provider, Network Location Provider, and
476 Fused Location Provider. They will each be searched for
477 service components implementing these providers.
478 The location framework also has support for installation
479 of new location providers at run-time. The new package does not
480 have to be explicitly listed here, however it must have a signature
481 that matches the signature of at least one package on this list.
482 */
483 Resources resources = mContext.getResources();
484 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500485 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700486 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500487 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
488 Arrays.toString(pkgs));
489 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
490
491 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700492
493 // bind to network provider
494 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
495 mContext,
496 LocationManager.NETWORK_PROVIDER,
497 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700498 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
499 com.android.internal.R.string.config_networkLocationProviderPackageName,
500 com.android.internal.R.array.config_locationProviderPackageNames,
501 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700502 if (networkProvider != null) {
503 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
504 mProxyProviders.add(networkProvider);
505 addProviderLocked(networkProvider);
506 } else {
507 Slog.w(TAG, "no network location provider found");
508 }
509
510 // bind to fused provider
511 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
512 mContext,
513 LocationManager.FUSED_PROVIDER,
514 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700515 com.android.internal.R.bool.config_enableFusedLocationOverlay,
516 com.android.internal.R.string.config_fusedLocationProviderPackageName,
517 com.android.internal.R.array.config_locationProviderPackageNames,
518 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700519 if (fusedLocationProvider != null) {
520 addProviderLocked(fusedLocationProvider);
521 mProxyProviders.add(fusedLocationProvider);
522 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700523 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700524 } else {
525 Slog.e(TAG, "no fused location provider found",
526 new IllegalStateException("Location service needs a fused location provider"));
527 }
528
529 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700530 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
531 com.android.internal.R.bool.config_enableGeocoderOverlay,
532 com.android.internal.R.string.config_geocoderProviderPackageName,
533 com.android.internal.R.array.config_locationProviderPackageNames,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800534 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700535 if (mGeocodeProvider == null) {
536 Slog.e(TAG, "no geocoder provider found");
537 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700538
destradaaa4fa3b52014-07-09 10:46:39 -0700539 // bind to fused hardware provider if supported
destradaabeea4422014-07-30 18:17:21 -0700540 // in devices without support, requesting an instance of FlpHardwareProvider will raise an
541 // exception, so make sure we only do that when supported
542 FlpHardwareProvider flpHardwareProvider;
destradaa5ce66d82014-05-28 18:24:08 -0700543 if (FlpHardwareProvider.isSupported()) {
destradaabeea4422014-07-30 18:17:21 -0700544 flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
destradaaf9a274c2014-07-25 15:11:56 -0700545 FusedProxy fusedProxy = FusedProxy.createAndBind(
546 mContext,
547 mLocationHandler,
548 flpHardwareProvider.getLocationHardware(),
549 com.android.internal.R.bool.config_enableHardwareFlpOverlay,
550 com.android.internal.R.string.config_hardwareFlpPackageName,
551 com.android.internal.R.array.config_locationProviderPackageNames);
552 if (fusedProxy == null) {
destradaa6b4893a2016-05-03 15:33:43 -0700553 Slog.d(TAG, "Unable to bind FusedProxy.");
destradaaf9a274c2014-07-25 15:11:56 -0700554 }
destradaacfbdcd22014-04-30 11:29:11 -0700555 } else {
destradaabeea4422014-07-30 18:17:21 -0700556 flpHardwareProvider = null;
destradaa6b4893a2016-05-03 15:33:43 -0700557 Slog.d(TAG, "FLP HAL not supported");
destradaaf9a274c2014-07-25 15:11:56 -0700558 }
559
560 // bind to geofence provider
561 GeofenceProxy provider = GeofenceProxy.createAndBind(
562 mContext,com.android.internal.R.bool.config_enableGeofenceOverlay,
563 com.android.internal.R.string.config_geofenceProviderPackageName,
564 com.android.internal.R.array.config_locationProviderPackageNames,
565 mLocationHandler,
Wei Liu5241a4c2015-05-11 14:00:36 -0700566 mGpsGeofenceProxy,
destradaabeea4422014-07-30 18:17:21 -0700567 flpHardwareProvider != null ? flpHardwareProvider.getGeofenceHardware() : null);
destradaaf9a274c2014-07-25 15:11:56 -0700568 if (provider == null) {
destradaa6b4893a2016-05-03 15:33:43 -0700569 Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
destradaa0682809a2013-08-12 18:50:30 -0700570 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900571
destradaa6e2fe752015-06-23 17:25:53 -0700572 // bind to hardware activity recognition
573 boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported();
574 ActivityRecognitionHardware activityRecognitionHardware = null;
575 if (activityRecognitionHardwareIsSupported) {
576 activityRecognitionHardware = ActivityRecognitionHardware.getInstance(mContext);
destradaaa4fa3b52014-07-09 10:46:39 -0700577 } else {
destradaa6b4893a2016-05-03 15:33:43 -0700578 Slog.d(TAG, "Hardware Activity-Recognition not supported.");
destradaaa4fa3b52014-07-09 10:46:39 -0700579 }
destradaa6e2fe752015-06-23 17:25:53 -0700580 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
581 mContext,
582 mLocationHandler,
583 activityRecognitionHardwareIsSupported,
584 activityRecognitionHardware,
585 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
586 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
587 com.android.internal.R.array.config_locationProviderPackageNames);
588 if (proxy == null) {
destradaa6b4893a2016-05-03 15:33:43 -0700589 Slog.d(TAG, "Unable to bind ActivityRecognitionProxy.");
destradaa6e2fe752015-06-23 17:25:53 -0700590 }
destradaaa4fa3b52014-07-09 10:46:39 -0700591
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900592 String[] testProviderStrings = resources.getStringArray(
593 com.android.internal.R.array.config_testLocationProviders);
594 for (String testProviderString : testProviderStrings) {
595 String fragments[] = testProviderString.split(",");
596 String name = fragments[0].trim();
597 if (mProvidersByName.get(name) != null) {
598 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
599 }
600 ProviderProperties properties = new ProviderProperties(
601 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
602 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
603 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
604 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
605 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
606 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
607 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
608 Integer.parseInt(fragments[8]) /* powerRequirement */,
609 Integer.parseInt(fragments[9]) /* accuracy */);
610 addTestProviderLocked(name, properties);
611 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700612 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700613
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700615 * Called when the device's active user changes.
616 * @param userId the new active user's UserId
617 */
618 private void switchUser(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800619 if (mCurrentUserId == userId) {
620 return;
621 }
Victoria Lease83762d22012-10-03 13:51:17 -0700622 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800623 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700624 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700625 mLastLocation.clear();
David Christie1b9b7b12013-04-15 15:31:11 -0700626 mLastLocationCoarseInterval.clear();
Victoria Leaseb711d572012-10-02 13:14:11 -0700627 for (LocationProviderInterface p : mProviders) {
Amith Yamasanib27528d2014-06-05 15:02:10 -0700628 updateProviderListenersLocked(p.getName(), false);
Victoria Leaseb711d572012-10-02 13:14:11 -0700629 }
Victoria Lease38389b62012-09-30 11:44:22 -0700630 mCurrentUserId = userId;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700631 updateUserProfiles(userId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700632 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700633 }
634 }
635
636 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
638 * location updates.
639 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700640 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700641 final int mUid; // uid of receiver
642 final int mPid; // pid of receiver
643 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700644 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700645
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 final ILocationListener mListener;
647 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -0700648 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
David Christie40e57822013-07-30 11:36:48 -0700649 final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700651
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400652 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700653
David Christie0b837452013-07-29 16:02:13 -0700654 // True if app ops has started monitoring this receiver for locations.
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700655 boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -0700656 // True if app ops has started monitoring this receiver for high power (gps) locations.
657 boolean mOpHighPowerMonitoring;
Mike Lockwood48f17512009-04-23 09:12:08 -0700658 int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -0700659 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700661 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -0700662 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800663 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700665 if (listener != null) {
666 mKey = listener.asBinder();
667 } else {
668 mKey = intent;
669 }
Victoria Lease37425c32012-10-16 16:08:48 -0700670 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700671 mUid = uid;
672 mPid = pid;
673 mPackageName = packageName;
David Christie82edc9b2013-07-19 11:31:42 -0700674 if (workSource != null && workSource.size() <= 0) {
675 workSource = null;
676 }
677 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -0700678 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -0700679
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700680 updateMonitoring(true);
681
Victoria Lease0aa28602013-05-29 15:28:26 -0700682 // construct/configure wakelock
683 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -0700684 if (workSource == null) {
685 workSource = new WorkSource(mUid, mPackageName);
686 }
687 mWakeLock.setWorkSource(workSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 }
689
690 @Override
691 public boolean equals(Object otherObj) {
692 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700693 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694 }
695 return false;
696 }
697
698 @Override
699 public int hashCode() {
700 return mKey.hashCode();
701 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400702
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703 @Override
704 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700705 StringBuilder s = new StringBuilder();
706 s.append("Reciever[");
707 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700709 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800710 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700711 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700713 for (String p : mUpdateRecords.keySet()) {
714 s.append(" ").append(mUpdateRecords.get(p).toString());
715 }
716 s.append("]");
717 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800718 }
719
David Christie15b31912013-08-13 15:54:32 -0700720 /**
721 * Update AppOp monitoring for this receiver.
722 *
723 * @param allow If true receiver is currently active, if false it's been removed.
724 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700725 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -0700726 if (mHideFromAppOps) {
727 return;
728 }
729
David Christie15b31912013-08-13 15:54:32 -0700730 boolean requestingLocation = false;
731 boolean requestingHighPowerLocation = false;
732 if (allow) {
733 // See if receiver has any enabled update records. Also note if any update records
734 // are high power (has a high power provider with an interval under a threshold).
735 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
736 if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) {
737 requestingLocation = true;
738 LocationProviderInterface locationProvider
David Christie2ff96af2014-01-30 16:09:37 -0800739 = mProvidersByName.get(updateRecord.mProvider);
David Christie15b31912013-08-13 15:54:32 -0700740 ProviderProperties properties = locationProvider != null
741 ? locationProvider.getProperties() : null;
742 if (properties != null
743 && properties.mPowerRequirement == Criteria.POWER_HIGH
744 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
745 requestingHighPowerLocation = true;
746 break;
747 }
748 }
749 }
750 }
751
David Christie0b837452013-07-29 16:02:13 -0700752 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -0700753 mOpMonitoring = updateMonitoring(
754 requestingLocation,
755 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700756 AppOpsManager.OP_MONITOR_LOCATION);
757
758 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -0700759 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -0700760 mOpHighPowerMonitoring = updateMonitoring(
761 requestingHighPowerLocation,
762 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700763 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -0700764 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -0700765 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -0700766 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
767 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
768 }
David Christie0b837452013-07-29 16:02:13 -0700769 }
770
771 /**
772 * Update AppOps monitoring for a single location request and op type.
773 *
774 * @param allowMonitoring True if monitoring is allowed for this request/op.
775 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
776 * @param op AppOps code for the op to update.
777 * @return True if monitoring is on for this request/op after updating.
778 */
779 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
780 int op) {
781 if (!currentlyMonitoring) {
782 if (allowMonitoring) {
783 return mAppOps.startOpNoThrow(op, mUid, mPackageName)
784 == AppOpsManager.MODE_ALLOWED;
785 }
786 } else {
787 if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
788 != AppOpsManager.MODE_ALLOWED) {
789 mAppOps.finishOp(op, mUid, mPackageName);
790 return false;
791 }
792 }
793
794 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700795 }
796
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 public boolean isListener() {
798 return mListener != null;
799 }
800
801 public boolean isPendingIntent() {
802 return mPendingIntent != null;
803 }
804
805 public ILocationListener getListener() {
806 if (mListener != null) {
807 return mListener;
808 }
809 throw new IllegalStateException("Request for non-existent listener");
810 }
811
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
813 if (mListener != null) {
814 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700815 synchronized (this) {
816 // synchronize to ensure incrementPendingBroadcastsLocked()
817 // is called before decrementPendingBroadcasts()
818 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700819 // call this after broadcasting so we do not increment
820 // if we throw an exeption.
821 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700822 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 } catch (RemoteException e) {
824 return false;
825 }
826 } else {
827 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800828 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
830 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700831 synchronized (this) {
832 // synchronize to ensure incrementPendingBroadcastsLocked()
833 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700834 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700835 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700836 // call this after broadcasting so we do not increment
837 // if we throw an exeption.
838 incrementPendingBroadcastsLocked();
839 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800840 } catch (PendingIntent.CanceledException e) {
841 return false;
842 }
843 }
844 return true;
845 }
846
847 public boolean callLocationChangedLocked(Location location) {
848 if (mListener != null) {
849 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700850 synchronized (this) {
851 // synchronize to ensure incrementPendingBroadcastsLocked()
852 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800853 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700854 // call this after broadcasting so we do not increment
855 // if we throw an exeption.
856 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700857 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 } catch (RemoteException e) {
859 return false;
860 }
861 } else {
862 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800863 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700865 synchronized (this) {
866 // synchronize to ensure incrementPendingBroadcastsLocked()
867 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700868 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700869 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700870 // call this after broadcasting so we do not increment
871 // if we throw an exeption.
872 incrementPendingBroadcastsLocked();
873 }
874 } catch (PendingIntent.CanceledException e) {
875 return false;
876 }
877 }
878 return true;
879 }
880
881 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -0700882 // First update AppOp monitoring.
883 // An app may get/lose location access as providers are enabled/disabled.
884 updateMonitoring(true);
885
Mike Lockwood48f17512009-04-23 09:12:08 -0700886 if (mListener != null) {
887 try {
888 synchronized (this) {
889 // synchronize to ensure incrementPendingBroadcastsLocked()
890 // is called before decrementPendingBroadcasts()
891 if (enabled) {
892 mListener.onProviderEnabled(provider);
893 } else {
894 mListener.onProviderDisabled(provider);
895 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700896 // call this after broadcasting so we do not increment
897 // if we throw an exeption.
898 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700899 }
900 } catch (RemoteException e) {
901 return false;
902 }
903 } else {
904 Intent providerIntent = new Intent();
905 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
906 try {
907 synchronized (this) {
908 // synchronize to ensure incrementPendingBroadcastsLocked()
909 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700910 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700911 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700912 // call this after broadcasting so we do not increment
913 // if we throw an exeption.
914 incrementPendingBroadcastsLocked();
915 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916 } catch (PendingIntent.CanceledException e) {
917 return false;
918 }
919 }
920 return true;
921 }
922
Nick Pellyf1be6862012-05-15 10:53:42 -0700923 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700925 if (D) Log.d(TAG, "Location listener died");
926
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400927 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928 removeUpdatesLocked(this);
929 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700930 synchronized (this) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700931 clearPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700932 }
933 }
934
Nick Pellye0fd6932012-07-11 10:26:13 -0700935 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700936 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
937 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400938 synchronized (this) {
939 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700940 }
941 }
942
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400943 // this must be called while synchronized by caller in a synchronized block
944 // containing the sending of the broadcaset
945 private void incrementPendingBroadcastsLocked() {
946 if (mPendingBroadcasts++ == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700947 mWakeLock.acquire();
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400948 }
949 }
950
951 private void decrementPendingBroadcastsLocked() {
952 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700953 if (mWakeLock.isHeld()) {
954 mWakeLock.release();
955 }
956 }
957 }
958
959 public void clearPendingBroadcastsLocked() {
960 if (mPendingBroadcasts > 0) {
961 mPendingBroadcasts = 0;
962 if (mWakeLock.isHeld()) {
963 mWakeLock.release();
964 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700965 }
966 }
967 }
968
Nick Pellye0fd6932012-07-11 10:26:13 -0700969 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700970 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700971 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -0400972 //the receiver list if it is not found. If it is not found then the
973 //LocationListener was removed when it had a pending broadcast and should
974 //not be added back.
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700975 synchronized (mLock) {
976 IBinder binder = listener.asBinder();
977 Receiver receiver = mReceivers.get(binder);
978 if (receiver != null) {
979 synchronized (receiver) {
980 // so wakelock calls will succeed
981 long identity = Binder.clearCallingIdentity();
982 receiver.decrementPendingBroadcastsLocked();
983 Binder.restoreCallingIdentity(identity);
David Christie2ff96af2014-01-30 16:09:37 -0800984 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700985 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 }
987 }
988
Lifu Tang82f893d2016-01-21 18:15:33 -0800989 /**
Lifu Tang9363b942016-02-16 18:07:00 -0800990 * Returns the system information of the GNSS hardware.
Lifu Tang82f893d2016-01-21 18:15:33 -0800991 */
992 @Override
Lifu Tang9363b942016-02-16 18:07:00 -0800993 public int getGnssYearOfHardware() {
Lifu Tang818aa2c2016-02-01 01:52:00 -0800994 if (mGnssNavigationMessageProvider != null) {
Lifu Tang9363b942016-02-16 18:07:00 -0800995 return mGnssSystemInfoProvider.getGnssYearOfHardware();
Lifu Tang82f893d2016-01-21 18:15:33 -0800996 } else {
997 return 0;
998 }
999 }
1000
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001001 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001002 mProviders.add(provider);
1003 mProvidersByName.put(provider.getName(), provider);
1004 }
1005
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001006 private void removeProviderLocked(LocationProviderInterface provider) {
1007 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001008 mProviders.remove(provider);
1009 mProvidersByName.remove(provider.getName());
1010 }
1011
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001012 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -08001013 * Returns "true" if access to the specified location provider is allowed by the current
1014 * user's settings. Access to all location providers is forbidden to non-location-provider
1015 * processes belonging to background users.
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001016 *
1017 * @param provider the name of the location provider
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001018 * @return
1019 */
Victoria Lease09eeaec2013-02-05 11:34:13 -08001020 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 if (mEnabledProviders.contains(provider)) {
1022 return true;
1023 }
1024 if (mDisabledProviders.contains(provider)) {
1025 return false;
1026 }
1027 // Use system settings
1028 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001029
Victoria Leaseb711d572012-10-02 13:14:11 -07001030 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 }
1032
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001033 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -08001034 * Returns "true" if access to the specified location provider is allowed by the specified
1035 * user's settings. Access to all location providers is forbidden to non-location-provider
1036 * processes belonging to background users.
1037 *
1038 * @param provider the name of the location provider
1039 * @param uid the requestor's UID
1040 * @return
1041 */
1042 private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001043 if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001044 return false;
1045 }
1046 return isAllowedByCurrentUserSettingsLocked(provider);
1047 }
1048
1049 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001050 * Returns the permission string associated with the specified resolution level.
1051 *
1052 * @param resolutionLevel the resolution level
1053 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001054 */
Victoria Lease37425c32012-10-16 16:08:48 -07001055 private String getResolutionPermission(int resolutionLevel) {
1056 switch (resolutionLevel) {
1057 case RESOLUTION_LEVEL_FINE:
1058 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1059 case RESOLUTION_LEVEL_COARSE:
1060 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1061 default:
1062 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001063 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001064 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001065
Victoria Leaseda479c52012-10-15 15:24:16 -07001066 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001067 * Returns the resolution level allowed to the given PID/UID pair.
1068 *
1069 * @param pid the PID
1070 * @param uid the UID
1071 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -07001072 */
Victoria Lease37425c32012-10-16 16:08:48 -07001073 private int getAllowedResolutionLevel(int pid, int uid) {
1074 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
1075 pid, uid) == PackageManager.PERMISSION_GRANTED) {
1076 return RESOLUTION_LEVEL_FINE;
1077 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
1078 pid, uid) == PackageManager.PERMISSION_GRANTED) {
1079 return RESOLUTION_LEVEL_COARSE;
1080 } else {
1081 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001082 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001083 }
1084
1085 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001086 * Returns the resolution level allowed to the caller
1087 *
1088 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -07001089 */
Victoria Lease37425c32012-10-16 16:08:48 -07001090 private int getCallerAllowedResolutionLevel() {
1091 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1092 }
1093
1094 /**
1095 * Throw SecurityException if specified resolution level is insufficient to use geofences.
1096 *
1097 * @param allowedResolutionLevel resolution level allowed to caller
1098 */
1099 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1100 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001101 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1102 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 }
1104
Victoria Lease37425c32012-10-16 16:08:48 -07001105 /**
1106 * Return the minimum resolution level required to use the specified location provider.
1107 *
1108 * @param provider the name of the location provider
1109 * @return minimum resolution level required for provider
1110 */
1111 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001112 if (LocationManager.GPS_PROVIDER.equals(provider) ||
1113 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1114 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001115 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -07001116 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1117 LocationManager.FUSED_PROVIDER.equals(provider)) {
1118 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001119 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001120 } else {
1121 // mock providers
1122 LocationProviderInterface lp = mMockProviders.get(provider);
1123 if (lp != null) {
1124 ProviderProperties properties = lp.getProperties();
1125 if (properties != null) {
1126 if (properties.mRequiresSatellite) {
1127 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001128 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001129 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1130 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001131 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001132 }
1133 }
1134 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001135 }
Victoria Lease37425c32012-10-16 16:08:48 -07001136 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001137 }
1138
Victoria Lease37425c32012-10-16 16:08:48 -07001139 /**
1140 * Throw SecurityException if specified resolution level is insufficient to use the named
1141 * location provider.
1142 *
1143 * @param allowedResolutionLevel resolution level allowed to caller
1144 * @param providerName the name of the location provider
1145 */
1146 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1147 String providerName) {
1148 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1149 if (allowedResolutionLevel < requiredResolutionLevel) {
1150 switch (requiredResolutionLevel) {
1151 case RESOLUTION_LEVEL_FINE:
1152 throw new SecurityException("\"" + providerName + "\" location provider " +
1153 "requires ACCESS_FINE_LOCATION permission.");
1154 case RESOLUTION_LEVEL_COARSE:
1155 throw new SecurityException("\"" + providerName + "\" location provider " +
1156 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1157 default:
1158 throw new SecurityException("Insufficient permission for \"" + providerName +
1159 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001160 }
1161 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001162 }
1163
David Christie82edc9b2013-07-19 11:31:42 -07001164 /**
1165 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
1166 * for battery).
1167 */
David Christie40e57822013-07-30 11:36:48 -07001168 private void checkDeviceStatsAllowed() {
David Christie82edc9b2013-07-19 11:31:42 -07001169 mContext.enforceCallingOrSelfPermission(
1170 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
1171 }
1172
David Christie40e57822013-07-30 11:36:48 -07001173 private void checkUpdateAppOpsAllowed() {
1174 mContext.enforceCallingOrSelfPermission(
1175 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
1176 }
1177
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001178 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001179 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1180 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001181 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001182 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001183 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001184 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001185 }
1186 return -1;
1187 }
1188
David Christieb870dbf2015-06-22 12:42:53 -07001189 boolean reportLocationAccessNoThrow(
1190 int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001191 int op = resolutionLevelToOp(allowedResolutionLevel);
1192 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001193 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1194 return false;
1195 }
1196 }
David Christieb870dbf2015-06-22 12:42:53 -07001197
1198 if (getAllowedResolutionLevel(pid, uid) < allowedResolutionLevel) {
1199 return false;
1200 }
1201
Dianne Hackborn35654b62013-01-14 17:38:02 -08001202 return true;
1203 }
1204
David Christieb870dbf2015-06-22 12:42:53 -07001205 boolean checkLocationAccess(int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001206 int op = resolutionLevelToOp(allowedResolutionLevel);
1207 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001208 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1209 return false;
1210 }
1211 }
David Christieb870dbf2015-06-22 12:42:53 -07001212
1213 if (getAllowedResolutionLevel(pid, uid) < allowedResolutionLevel) {
1214 return false;
1215 }
1216
Dianne Hackborn35654b62013-01-14 17:38:02 -08001217 return true;
1218 }
1219
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001220 /**
1221 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -07001222 * fused, also including ones that are not permitted to
1223 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001224 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001225 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001227 ArrayList<String> out;
1228 synchronized (mLock) {
1229 out = new ArrayList<String>(mProviders.size());
1230 for (LocationProviderInterface provider : mProviders) {
1231 String name = provider.getName();
1232 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001233 continue;
1234 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001235 out.add(name);
1236 }
1237 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001238
1239 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001240 return out;
1241 }
1242
Mike Lockwood03ca2162010-04-01 08:10:09 -07001243 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001244 * Return all providers by name, that match criteria and are optionally
1245 * enabled.
1246 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001247 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001248 @Override
1249 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001250 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001251 ArrayList<String> out;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001252 int uid = Binder.getCallingUid();;
Victoria Lease269518e2012-10-29 08:25:39 -07001253 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001254 try {
1255 synchronized (mLock) {
1256 out = new ArrayList<String>(mProviders.size());
1257 for (LocationProviderInterface provider : mProviders) {
1258 String name = provider.getName();
1259 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001260 continue;
1261 }
Victoria Lease37425c32012-10-16 16:08:48 -07001262 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001263 if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001264 continue;
1265 }
1266 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
1267 name, provider.getProperties(), criteria)) {
1268 continue;
1269 }
1270 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001271 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001272 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001273 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001274 } finally {
1275 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001276 }
1277
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001278 if (D) Log.d(TAG, "getProviders()=" + out);
1279 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001280 }
1281
1282 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001283 * Return the name of the best provider given a Criteria object.
1284 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001285 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001286 * has been deprecated as well. So this method now uses
1287 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001288 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001289 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001290 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001291 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001292
1293 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001294 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001295 result = pickBest(providers);
1296 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1297 return result;
1298 }
1299 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001300 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001301 result = pickBest(providers);
1302 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1303 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001304 }
1305
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001306 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001307 return null;
1308 }
1309
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001310 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -07001311 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001312 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -07001313 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1314 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001315 } else {
1316 return providers.get(0);
1317 }
1318 }
1319
Nick Pellye0fd6932012-07-11 10:26:13 -07001320 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001321 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1322 LocationProviderInterface p = mProvidersByName.get(provider);
1323 if (p == null) {
1324 throw new IllegalArgumentException("provider=" + provider);
1325 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001326
1327 boolean result = LocationProvider.propertiesMeetCriteria(
1328 p.getName(), p.getProperties(), criteria);
1329 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1330 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001331 }
1332
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001334 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001335 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001336 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001337 boolean isEnabled = p.isEnabled();
1338 String name = p.getName();
Victoria Lease09eeaec2013-02-05 11:34:13 -08001339 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001340 if (isEnabled && !shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001341 updateProviderListenersLocked(name, false);
David Christieb084fef2013-12-18 14:33:57 -08001342 // If any provider has been disabled, clear all last locations for all providers.
1343 // This is to be on the safe side in case a provider has location derived from
1344 // this disabled provider.
1345 mLastLocation.clear();
1346 mLastLocationCoarseInterval.clear();
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001347 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001348 } else if (!isEnabled && shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001349 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001350 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001351 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001352 }
1353 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001354 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1355 UserHandle.ALL);
Tom O'Neill40a86c22013-09-03 18:05:13 -07001356 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1357 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001358 }
1359 }
1360
Amith Yamasanib27528d2014-06-05 15:02:10 -07001361 private void updateProviderListenersLocked(String provider, boolean enabled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001362 int listeners = 0;
1363
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001364 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001365 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366
1367 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001368
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1370 if (records != null) {
1371 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001372 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001373 UpdateRecord record = records.get(i);
Amith Yamasanib27528d2014-06-05 15:02:10 -07001374 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001375 // Sends a notification message to the receiver
1376 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1377 if (deadReceivers == null) {
1378 deadReceivers = new ArrayList<Receiver>();
1379 }
1380 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001381 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001382 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001383 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384 }
1385 }
1386
1387 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001388 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389 removeUpdatesLocked(deadReceivers.get(i));
1390 }
1391 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001392
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001393 if (enabled) {
1394 p.enable();
1395 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001396 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001397 }
1398 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001399 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001400 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401 }
1402
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001403 private void applyRequirementsLocked(String provider) {
1404 LocationProviderInterface p = mProvidersByName.get(provider);
1405 if (p == null) return;
1406
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001407 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001408 WorkSource worksource = new WorkSource();
1409 ProviderRequest providerRequest = new ProviderRequest();
1410
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001411 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001412 for (UpdateRecord record : records) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001413 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
David Christieb870dbf2015-06-22 12:42:53 -07001414 if (checkLocationAccess(
1415 record.mReceiver.mPid,
1416 record.mReceiver.mUid,
1417 record.mReceiver.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001418 record.mReceiver.mAllowedResolutionLevel)) {
1419 LocationRequest locationRequest = record.mRequest;
1420 providerRequest.locationRequests.add(locationRequest);
1421 if (locationRequest.getInterval() < providerRequest.interval) {
1422 providerRequest.reportLocation = true;
1423 providerRequest.interval = locationRequest.getInterval();
1424 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001425 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001426 }
1427 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001428
1429 if (providerRequest.reportLocation) {
1430 // calculate who to blame for power
1431 // This is somewhat arbitrary. We pick a threshold interval
1432 // that is slightly higher that the minimum interval, and
1433 // spread the blame across all applications with a request
1434 // under that threshold.
1435 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1436 for (UpdateRecord record : records) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001437 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001438 LocationRequest locationRequest = record.mRequest;
Svet Ganove998c732016-06-10 00:12:38 -07001439
1440 // Don't assign battery blame for update records whose
1441 // client has no permission to receive location data.
1442 if (!providerRequest.locationRequests.contains(locationRequest)) {
1443 continue;
1444 }
1445
Victoria Leaseb711d572012-10-02 13:14:11 -07001446 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07001447 if (record.mReceiver.mWorkSource != null
1448 && record.mReceiver.mWorkSource.size() > 0
1449 && record.mReceiver.mWorkSource.getName(0) != null) {
David Christie82edc9b2013-07-19 11:31:42 -07001450 // Assign blame to another work source.
David Christiee55c9682013-08-22 10:10:34 -07001451 // Can only assign blame if the WorkSource contains names.
David Christie82edc9b2013-07-19 11:31:42 -07001452 worksource.add(record.mReceiver.mWorkSource);
1453 } else {
1454 // Assign blame to caller.
1455 worksource.add(
1456 record.mReceiver.mUid,
1457 record.mReceiver.mPackageName);
1458 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001459 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001460 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001461 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001462 }
1463 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001464
1465 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1466 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001467 }
1468
1469 private class UpdateRecord {
1470 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001471 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001473 Location mLastFixBroadcast;
1474 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001475
1476 /**
1477 * Note: must be constructed with lock held.
1478 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001479 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001480 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001481 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001482 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001483
1484 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1485 if (records == null) {
1486 records = new ArrayList<UpdateRecord>();
1487 mRecordsByProvider.put(provider, records);
1488 }
1489 if (!records.contains(this)) {
1490 records.add(this);
1491 }
David Christie2ff96af2014-01-30 16:09:37 -08001492
1493 // Update statistics for historical location requests by package/provider
1494 mRequestStatistics.startRequesting(
1495 mReceiver.mPackageName, provider, request.getInterval());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001496 }
1497
1498 /**
David Christie2ff96af2014-01-30 16:09:37 -08001499 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001500 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001501 void disposeLocked(boolean removeReceiver) {
David Christie2ff96af2014-01-30 16:09:37 -08001502 mRequestStatistics.stopRequesting(mReceiver.mPackageName, mProvider);
1503
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001504 // remove from mRecordsByProvider
1505 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1506 if (globalRecords != null) {
1507 globalRecords.remove(this);
1508 }
1509
1510 if (!removeReceiver) return; // the caller will handle the rest
1511
1512 // remove from Receiver#mUpdateRecords
1513 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1514 if (receiverRecords != null) {
1515 receiverRecords.remove(this.mProvider);
1516
1517 // and also remove the Receiver if it has no more update records
1518 if (removeReceiver && receiverRecords.size() == 0) {
1519 removeUpdatesLocked(mReceiver);
1520 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001521 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001522 }
1523
1524 @Override
1525 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001526 StringBuilder s = new StringBuilder();
1527 s.append("UpdateRecord[");
1528 s.append(mProvider);
1529 s.append(' ').append(mReceiver.mPackageName).append('(');
1530 s.append(mReceiver.mUid).append(')');
1531 s.append(' ').append(mRequest);
1532 s.append(']');
1533 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001534 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001535 }
1536
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001537 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07001538 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001539 IBinder binder = listener.asBinder();
1540 Receiver receiver = mReceivers.get(binder);
1541 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001542 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
1543 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001544 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001545 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001546 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001547 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001548 return null;
1549 }
Wen Jingcb3ab222014-03-27 13:42:59 +08001550 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001551 }
1552 return receiver;
1553 }
1554
David Christie82edc9b2013-07-19 11:31:42 -07001555 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07001556 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001557 Receiver receiver = mReceivers.get(intent);
1558 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001559 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
1560 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001561 mReceivers.put(intent, receiver);
1562 }
1563 return receiver;
1564 }
1565
Victoria Lease37425c32012-10-16 16:08:48 -07001566 /**
1567 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1568 * and consistency requirements.
1569 *
1570 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07001571 * @return a version of request that meets the given resolution and consistency requirements
1572 * @hide
1573 */
1574 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1575 LocationRequest sanitizedRequest = new LocationRequest(request);
1576 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1577 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001578 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001579 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001580 break;
1581 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001582 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001583 break;
1584 }
1585 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001586 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1587 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001588 }
Victoria Lease37425c32012-10-16 16:08:48 -07001589 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1590 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001591 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001592 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001593 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001594 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001595 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001596 }
Victoria Lease37425c32012-10-16 16:08:48 -07001597 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001598 }
1599
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001600 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001601 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001602 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001603 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001604 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001605 String[] packages = mPackageManager.getPackagesForUid(uid);
1606 if (packages == null) {
1607 throw new SecurityException("invalid UID " + uid);
1608 }
1609 for (String pkg : packages) {
1610 if (packageName.equals(pkg)) return;
1611 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001612 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001613 }
1614
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001615 private void checkPendingIntent(PendingIntent intent) {
1616 if (intent == null) {
1617 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001618 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001619 }
1620
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001621 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
David Christie40e57822013-07-30 11:36:48 -07001622 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001623 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001624 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001625 } else if (intent != null && listener != null) {
1626 throw new IllegalArgumentException("cannot register both listener and intent");
1627 } else if (intent != null) {
1628 checkPendingIntent(intent);
David Christie40e57822013-07-30 11:36:48 -07001629 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001630 } else {
David Christie40e57822013-07-30 11:36:48 -07001631 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001632 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001633 }
1634
Nick Pellye0fd6932012-07-11 10:26:13 -07001635 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001636 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1637 PendingIntent intent, String packageName) {
1638 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1639 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001640 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1641 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1642 request.getProvider());
David Christie82edc9b2013-07-19 11:31:42 -07001643 WorkSource workSource = request.getWorkSource();
1644 if (workSource != null && workSource.size() > 0) {
David Christie40e57822013-07-30 11:36:48 -07001645 checkDeviceStatsAllowed();
1646 }
1647 boolean hideFromAppOps = request.getHideFromAppOps();
1648 if (hideFromAppOps) {
1649 checkUpdateAppOpsAllowed();
David Christie82edc9b2013-07-19 11:31:42 -07001650 }
Victoria Lease37425c32012-10-16 16:08:48 -07001651 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001652
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001653 final int pid = Binder.getCallingPid();
1654 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001655 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001656 long identity = Binder.clearCallingIdentity();
1657 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001658 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1659 // a location.
David Christieb870dbf2015-06-22 12:42:53 -07001660 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001661
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001662 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001663 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
David Christie40e57822013-07-30 11:36:48 -07001664 packageName, workSource, hideFromAppOps);
Victoria Lease37425c32012-10-16 16:08:48 -07001665 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001666 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001667 } finally {
1668 Binder.restoreCallingIdentity(identity);
1669 }
1670 }
1671
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001672 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1673 int pid, int uid, String packageName) {
1674 // Figure out the provider. Either its explicitly request (legacy use cases), or
1675 // use the fused provider
1676 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1677 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001678 if (name == null) {
1679 throw new IllegalArgumentException("provider name must not be null");
1680 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07001681
1682 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1683 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001684 LocationProviderInterface provider = mProvidersByName.get(name);
1685 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07001686 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001687 }
1688
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001689 UpdateRecord record = new UpdateRecord(name, request, receiver);
1690 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1691 if (oldRecord != null) {
1692 oldRecord.disposeLocked(false);
1693 }
1694
Victoria Lease09eeaec2013-02-05 11:34:13 -08001695 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001696 if (isProviderEnabled) {
1697 applyRequirementsLocked(name);
1698 } else {
1699 // Notify the listener that updates are currently disabled
1700 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701 }
David Christie0b837452013-07-29 16:02:13 -07001702 // Update the monitoring here just in case multiple location requests were added to the
1703 // same receiver (this request may be high power and the initial might not have been).
1704 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001705 }
1706
Nick Pellye0fd6932012-07-11 10:26:13 -07001707 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001708 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1709 String packageName) {
1710 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001711
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001712 final int pid = Binder.getCallingPid();
1713 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001714
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001715 synchronized (mLock) {
David Christie82edc9b2013-07-19 11:31:42 -07001716 WorkSource workSource = null;
David Christie40e57822013-07-30 11:36:48 -07001717 boolean hideFromAppOps = false;
1718 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
1719 packageName, workSource, hideFromAppOps);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001720
1721 // providers may use public location API's, need to clear identity
1722 long identity = Binder.clearCallingIdentity();
1723 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001724 removeUpdatesLocked(receiver);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001725 } finally {
1726 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001728 }
1729 }
1730
1731 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001732 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001733
1734 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1735 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1736 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001737 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001738 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001739 }
1740
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001741 receiver.updateMonitoring(false);
1742
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001743 // Record which providers were associated with this listener
1744 HashSet<String> providers = new HashSet<String>();
1745 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1746 if (oldRecords != null) {
1747 // Call dispose() on the obsolete update records.
1748 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08001749 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001750 record.disposeLocked(false);
1751 }
1752 // Accumulate providers
1753 providers.addAll(oldRecords.keySet());
1754 }
1755
1756 // update provider
1757 for (String provider : providers) {
1758 // If provider is already disabled, don't need to do anything
Victoria Lease09eeaec2013-02-05 11:34:13 -08001759 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001760 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 }
1762
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001763 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001764 }
1765 }
1766
Dianne Hackbornc2293022013-02-06 23:14:49 -08001767 private void applyAllProviderRequirementsLocked() {
1768 for (LocationProviderInterface p : mProviders) {
1769 // If provider is already disabled, don't need to do anything
Dianne Hackborn64d41d72013-02-07 00:33:31 -08001770 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08001771 continue;
1772 }
1773
1774 applyRequirementsLocked(p.getName());
1775 }
1776 }
1777
Nick Pellye0fd6932012-07-11 10:26:13 -07001778 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001779 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001780 if (D) Log.d(TAG, "getLastLocation: " + request);
1781 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001782 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001783 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001784 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1785 request.getProvider());
1786 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001787
David Christieb870dbf2015-06-22 12:42:53 -07001788 final int pid = Binder.getCallingPid();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001789 final int uid = Binder.getCallingUid();
1790 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001791 try {
1792 if (mBlacklist.isBlacklisted(packageName)) {
1793 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1794 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001795 return null;
1796 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001797
David Christieb870dbf2015-06-22 12:42:53 -07001798 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001799 if (D) Log.d(TAG, "not returning last loc for no op app: " +
1800 packageName);
1801 return null;
1802 }
1803
Victoria Leaseb711d572012-10-02 13:14:11 -07001804 synchronized (mLock) {
1805 // Figure out the provider. Either its explicitly request (deprecated API's),
1806 // or use the fused provider
1807 String name = request.getProvider();
1808 if (name == null) name = LocationManager.FUSED_PROVIDER;
1809 LocationProviderInterface provider = mProvidersByName.get(name);
1810 if (provider == null) return null;
1811
Victoria Lease09eeaec2013-02-05 11:34:13 -08001812 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001813
David Christie1b9b7b12013-04-15 15:31:11 -07001814 Location location;
1815 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1816 // Make sure that an app with coarse permissions can't get frequent location
1817 // updates by calling LocationManager.getLastKnownLocation repeatedly.
1818 location = mLastLocationCoarseInterval.get(name);
1819 } else {
1820 location = mLastLocation.get(name);
1821 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001822 if (location == null) {
1823 return null;
1824 }
Victoria Lease37425c32012-10-16 16:08:48 -07001825 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001826 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1827 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001828 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07001829 }
Victoria Lease37425c32012-10-16 16:08:48 -07001830 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001831 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07001832 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001833 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001834 return null;
1835 } finally {
1836 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001837 }
1838 }
1839
1840 @Override
1841 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1842 String packageName) {
1843 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001844 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1845 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001846 checkPendingIntent(intent);
1847 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001848 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1849 request.getProvider());
1850 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001851
Victoria Lease37425c32012-10-16 16:08:48 -07001852 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001853
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001854 // geo-fence manager uses the public location API, need to clear identity
1855 int uid = Binder.getCallingUid();
Xiaohui Chena4490622015-09-22 15:29:31 -07001856 // TODO: http://b/23822629
1857 if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
Victoria Lease56e675b2012-11-05 19:25:06 -08001858 // temporary measure until geofences work for secondary users
1859 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1860 return;
1861 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001862 long identity = Binder.clearCallingIdentity();
1863 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001864 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1865 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001866 } finally {
1867 Binder.restoreCallingIdentity(identity);
1868 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001869 }
1870
1871 @Override
1872 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001873 checkPendingIntent(intent);
1874 checkPackageName(packageName);
1875
1876 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1877
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001878 // geo-fence manager uses the public location API, need to clear identity
1879 long identity = Binder.clearCallingIdentity();
1880 try {
1881 mGeofenceManager.removeFence(geofence, intent);
1882 } finally {
1883 Binder.restoreCallingIdentity(identity);
1884 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001885 }
1886
1887
1888 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08001889 public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001890 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1891 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001892 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001893
David Christieb870dbf2015-06-22 12:42:53 -07001894 final int pid = Binder.getCallingPid();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001895 final int uid = Binder.getCallingUid();
1896 final long ident = Binder.clearCallingIdentity();
1897 try {
David Christieb870dbf2015-06-22 12:42:53 -07001898 if (!checkLocationAccess(pid, uid, packageName, allowedResolutionLevel)) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001899 return false;
1900 }
1901 } finally {
1902 Binder.restoreCallingIdentity(ident);
1903 }
1904
Lifu Tang30f95a72016-01-07 23:20:38 -08001905 if (mGnssStatusProvider == null) {
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09001906 return false;
1907 }
1908
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001909 try {
Lifu Tang30f95a72016-01-07 23:20:38 -08001910 mGnssStatusProvider.registerGnssStatusCallback(callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001911 } catch (RemoteException e) {
Lifu Tang30f95a72016-01-07 23:20:38 -08001912 Slog.e(TAG, "mGpsStatusProvider.registerGnssStatusCallback failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001913 return false;
1914 }
1915 return true;
1916 }
1917
Nick Pellye0fd6932012-07-11 10:26:13 -07001918 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08001919 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001920 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001921 try {
Lifu Tang30f95a72016-01-07 23:20:38 -08001922 mGnssStatusProvider.unregisterGnssStatusCallback(callback);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001923 } catch (Exception e) {
Lifu Tang30f95a72016-01-07 23:20:38 -08001924 Slog.e(TAG, "mGpsStatusProvider.unregisterGnssStatusCallback failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001925 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001926 }
1927 }
1928
Nick Pellye0fd6932012-07-11 10:26:13 -07001929 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08001930 public boolean addGnssMeasurementsListener(
1931 IGnssMeasurementsListener listener,
destradaaea8a8a62014-06-23 18:19:03 -07001932 String packageName) {
1933 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1934 checkResolutionLevelIsSufficientForProviderUse(
1935 allowedResolutionLevel,
1936 LocationManager.GPS_PROVIDER);
1937
David Christieb870dbf2015-06-22 12:42:53 -07001938 int pid = Binder.getCallingPid();
destradaaea8a8a62014-06-23 18:19:03 -07001939 int uid = Binder.getCallingUid();
1940 long identity = Binder.clearCallingIdentity();
1941 boolean hasLocationAccess;
1942 try {
David Christieb870dbf2015-06-22 12:42:53 -07001943 hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
destradaaea8a8a62014-06-23 18:19:03 -07001944 } finally {
1945 Binder.restoreCallingIdentity(identity);
1946 }
1947
Lifu Tang818aa2c2016-02-01 01:52:00 -08001948 if (!hasLocationAccess || mGnssMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07001949 return false;
1950 }
Lifu Tang818aa2c2016-02-01 01:52:00 -08001951 return mGnssMeasurementsProvider.addListener(listener);
destradaaea8a8a62014-06-23 18:19:03 -07001952 }
1953
1954 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08001955 public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
1956 if (mGnssMeasurementsProvider != null) {
1957 mGnssMeasurementsProvider.removeListener(listener);
Wei Liu5241a4c2015-05-11 14:00:36 -07001958 }
destradaaea8a8a62014-06-23 18:19:03 -07001959 }
1960
1961 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08001962 public boolean addGnssNavigationMessageListener(
1963 IGnssNavigationMessageListener listener,
destradaa4b3e3932014-07-21 18:01:47 -07001964 String packageName) {
1965 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1966 checkResolutionLevelIsSufficientForProviderUse(
1967 allowedResolutionLevel,
1968 LocationManager.GPS_PROVIDER);
1969
David Christieb870dbf2015-06-22 12:42:53 -07001970 int pid = Binder.getCallingPid();
destradaa4b3e3932014-07-21 18:01:47 -07001971 int uid = Binder.getCallingUid();
1972 long identity = Binder.clearCallingIdentity();
1973 boolean hasLocationAccess;
1974 try {
David Christieb870dbf2015-06-22 12:42:53 -07001975 hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
destradaa4b3e3932014-07-21 18:01:47 -07001976 } finally {
1977 Binder.restoreCallingIdentity(identity);
1978 }
1979
Lifu Tang818aa2c2016-02-01 01:52:00 -08001980 if (!hasLocationAccess || mGnssNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07001981 return false;
1982 }
Lifu Tang818aa2c2016-02-01 01:52:00 -08001983 return mGnssNavigationMessageProvider.addListener(listener);
destradaa4b3e3932014-07-21 18:01:47 -07001984 }
1985
1986 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08001987 public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
1988 if (mGnssNavigationMessageProvider != null) {
1989 mGnssNavigationMessageProvider.removeListener(listener);
Wei Liu5241a4c2015-05-11 14:00:36 -07001990 }
destradaa4b3e3932014-07-21 18:01:47 -07001991 }
1992
1993 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001994 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001995 if (provider == null) {
1996 // throw NullPointerException to remain compatible with previous implementation
1997 throw new NullPointerException();
1998 }
Victoria Lease37425c32012-10-16 16:08:48 -07001999 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2000 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002001
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002002 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04002003 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002004 != PackageManager.PERMISSION_GRANTED)) {
2005 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2006 }
2007
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002008 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002009 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002010 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07002011
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002012 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002013 }
2014 }
2015
Nick Pellye0fd6932012-07-11 10:26:13 -07002016 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002017 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07002018 if (Binder.getCallingUid() != Process.myUid()) {
2019 throw new SecurityException(
2020 "calling sendNiResponse from outside of the system is not allowed");
2021 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04002022 try {
2023 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002024 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002025 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04002026 return false;
2027 }
2028 }
2029
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002030 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002031 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11002032 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002033 * accessed by the caller
2034 */
Nick Pellye0fd6932012-07-11 10:26:13 -07002035 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002036 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07002037 if (mProvidersByName.get(provider) == null) {
David Christie2ff96af2014-01-30 16:09:37 -08002038 return null;
Laurent Tub7f9d252012-10-16 14:25:00 -07002039 }
2040
Victoria Lease37425c32012-10-16 16:08:48 -07002041 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2042 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002043
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002044 LocationProviderInterface p;
2045 synchronized (mLock) {
2046 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002047 }
2048
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002049 if (p == null) return null;
2050 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002051 }
2052
Jason Monkb71218a2015-06-17 14:44:39 -04002053 /**
2054 * @return null if the provider does not exist
2055 * @throws SecurityException if the provider is not allowed to be
2056 * accessed by the caller
2057 */
2058 @Override
2059 public String getNetworkProviderPackage() {
2060 LocationProviderInterface p;
2061 synchronized (mLock) {
2062 if (mProvidersByName.get(LocationManager.NETWORK_PROVIDER) == null) {
2063 return null;
2064 }
2065 p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
2066 }
2067
2068 if (p instanceof LocationProviderProxy) {
2069 return ((LocationProviderProxy) p).getConnectedPackageName();
2070 }
2071 return null;
2072 }
2073
Nick Pellye0fd6932012-07-11 10:26:13 -07002074 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002075 public boolean isProviderEnabled(String provider) {
Tom O'Neilld5759432013-09-11 11:03:03 -07002076 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2077 // so we discourage its use
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002078 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
2079
Victoria Lease09eeaec2013-02-05 11:34:13 -08002080 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07002081 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07002082 try {
2083 synchronized (mLock) {
2084 LocationProviderInterface p = mProvidersByName.get(provider);
2085 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002086
Victoria Lease09eeaec2013-02-05 11:34:13 -08002087 return isAllowedByUserSettingsLocked(provider, uid);
Victoria Leaseb711d572012-10-02 13:14:11 -07002088 }
2089 } finally {
2090 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002091 }
2092 }
2093
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002094 /**
2095 * Returns "true" if the UID belongs to a bound location provider.
2096 *
2097 * @param uid the uid
2098 * @return true if uid belongs to a bound location provider
2099 */
2100 private boolean isUidALocationProvider(int uid) {
2101 if (uid == Process.SYSTEM_UID) {
2102 return true;
2103 }
2104 if (mGeocodeProvider != null) {
David Christie1f141c12014-05-14 15:11:15 -07002105 if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002106 }
2107 for (LocationProviderProxy proxy : mProxyProviders) {
David Christie1f141c12014-05-14 15:11:15 -07002108 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002109 }
2110 return false;
2111 }
2112
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002113 private void checkCallerIsProvider() {
2114 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
2115 == PackageManager.PERMISSION_GRANTED) {
2116 return;
2117 }
2118
2119 // Previously we only used the INSTALL_LOCATION_PROVIDER
2120 // check. But that is system or signature
2121 // protection level which is not flexible enough for
2122 // providers installed oustide the system image. So
2123 // also allow providers with a UID matching the
2124 // currently bound package name
2125
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002126 if (isUidALocationProvider(Binder.getCallingUid())) {
2127 return;
2128 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002129
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002130 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2131 "or UID of a currently bound location provider");
2132 }
2133
David Christie1f141c12014-05-14 15:11:15 -07002134 /**
2135 * Returns true if the given package belongs to the given uid.
2136 */
2137 private boolean doesUidHavePackage(int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002138 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002139 return false;
2140 }
David Christie1f141c12014-05-14 15:11:15 -07002141 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2142 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002143 return false;
2144 }
David Christie1f141c12014-05-14 15:11:15 -07002145 for (String name : packageNames) {
2146 if (packageName.equals(name)) {
2147 return true;
2148 }
2149 }
2150 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002151 }
2152
Nick Pellye0fd6932012-07-11 10:26:13 -07002153 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05002154 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002155 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04002156
Nick Pelly2eeeec22012-07-18 13:13:37 -07002157 if (!location.isComplete()) {
2158 Log.w(TAG, "Dropping incomplete location: " + location);
2159 return;
2160 }
2161
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002162 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2163 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05002164 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002165 mLocationHandler.sendMessageAtFrontOfQueue(m);
2166 }
2167
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002168
Laurent Tu75defb62012-11-01 16:21:52 -07002169 private static boolean shouldBroadcastSafe(
2170 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002171 // Always broadcast the first update
2172 if (lastLoc == null) {
2173 return true;
2174 }
2175
Nick Pellyf1be6862012-05-15 10:53:42 -07002176 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002177 long minTime = record.mRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002178 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2179 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002180 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002181 return false;
2182 }
2183
2184 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002185 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002186 if (minDistance > 0.0) {
2187 if (loc.distanceTo(lastLoc) <= minDistance) {
2188 return false;
2189 }
2190 }
2191
Laurent Tu75defb62012-11-01 16:21:52 -07002192 // Check whether sufficient number of udpates is left
2193 if (record.mRequest.getNumUpdates() <= 0) {
2194 return false;
2195 }
2196
2197 // Check whether the expiry date has passed
2198 if (record.mRequest.getExpireAt() < now) {
2199 return false;
2200 }
2201
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002202 return true;
2203 }
2204
Mike Lockwooda4903f22010-02-17 06:42:23 -05002205 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002206 if (D) Log.d(TAG, "incoming location: " + location);
2207
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002208 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05002209 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002210
Laurent Tu60ec50a2012-10-04 17:00:10 -07002211 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002212 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002213 if (p == null) return;
2214
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002215 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07002216 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2217 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002218 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002219 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002220 lastLocation = new Location(provider);
2221 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07002222 } else {
2223 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2224 if (noGPSLocation == null && lastNoGPSLocation != null) {
2225 // New location has no no-GPS location: adopt last no-GPS location. This is set
2226 // directly into location because we do not want to notify COARSE clients.
2227 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
2228 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07002229 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002230 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002231
David Christie1b9b7b12013-04-15 15:31:11 -07002232 // Update last known coarse interval location if enough time has passed.
2233 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2234 if (lastLocationCoarseInterval == null) {
2235 lastLocationCoarseInterval = new Location(location);
2236 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2237 }
2238 long timeDiffNanos = location.getElapsedRealtimeNanos()
2239 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2240 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
2241 lastLocationCoarseInterval.set(location);
2242 }
2243 // Don't ever return a coarse location that is more recent than the allowed update
2244 // interval (i.e. don't allow an app to keep registering and unregistering for
2245 // location updates to overcome the minimum interval).
2246 noGPSLocation =
2247 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2248
Laurent Tu60ec50a2012-10-04 17:00:10 -07002249 // Skip if there are no UpdateRecords for this provider.
2250 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2251 if (records == null || records.size() == 0) return;
2252
Victoria Lease09016ab2012-09-16 12:33:15 -07002253 // Fetch coarse location
2254 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07002255 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002256 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2257 }
2258
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002259 // Fetch latest status update time
2260 long newStatusUpdateTime = p.getStatusUpdateTime();
2261
David Christie2ff96af2014-01-30 16:09:37 -08002262 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002263 Bundle extras = new Bundle();
2264 int status = p.getStatus(extras);
2265
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002266 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002267 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07002268
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002269 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002270 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002271 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07002272 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07002273
Victoria Lease269518e2012-10-29 08:25:39 -07002274 int receiverUserId = UserHandle.getUserId(receiver.mUid);
Amith Yamasanib27528d2014-06-05 15:02:10 -07002275 if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07002276 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07002277 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07002278 " (current user: " + mCurrentUserId + ", app: " +
2279 receiver.mPackageName + ")");
2280 }
2281 continue;
2282 }
2283
Nick Pelly4035f5a2012-08-17 14:43:49 -07002284 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
2285 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
2286 receiver.mPackageName);
2287 continue;
2288 }
2289
David Christieb870dbf2015-06-22 12:42:53 -07002290 if (!reportLocationAccessNoThrow(receiver.mPid, receiver.mUid, receiver.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002291 receiver.mAllowedResolutionLevel)) {
2292 if (D) Log.d(TAG, "skipping loc update for no op app: " +
2293 receiver.mPackageName);
2294 continue;
2295 }
2296
Victoria Lease09016ab2012-09-16 12:33:15 -07002297 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07002298 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2299 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002300 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07002301 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002302 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002303 if (notifyLocation != null) {
2304 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07002305 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002306 if (lastLoc == null) {
2307 lastLoc = new Location(notifyLocation);
2308 r.mLastFixBroadcast = lastLoc;
2309 } else {
2310 lastLoc.set(notifyLocation);
2311 }
2312 if (!receiver.callLocationChangedLocked(notifyLocation)) {
2313 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2314 receiverDead = true;
2315 }
Laurent Tu75defb62012-11-01 16:21:52 -07002316 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002317 }
2318 }
2319
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002320 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002321 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07002322 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002323
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002324 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002325 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002326 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08002327 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07002328 }
2329 }
2330
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002331 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07002332 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002333 if (deadUpdateRecords == null) {
2334 deadUpdateRecords = new ArrayList<UpdateRecord>();
2335 }
2336 deadUpdateRecords.add(r);
2337 }
2338 // track dead receivers
2339 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002340 if (deadReceivers == null) {
2341 deadReceivers = new ArrayList<Receiver>();
2342 }
2343 if (!deadReceivers.contains(receiver)) {
2344 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002345 }
2346 }
2347 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002348
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002349 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002350 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002351 for (Receiver receiver : deadReceivers) {
2352 removeUpdatesLocked(receiver);
2353 }
2354 }
2355 if (deadUpdateRecords != null) {
2356 for (UpdateRecord r : deadUpdateRecords) {
2357 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002358 }
Victoria Lease8b38b292012-12-04 15:04:43 -08002359 applyRequirementsLocked(provider);
2360 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002361 }
2362
2363 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08002364 public LocationWorkerHandler(Looper looper) {
2365 super(looper, null, true);
2366 }
2367
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002368 @Override
2369 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002370 switch (msg.what) {
2371 case MSG_LOCATION_CHANGED:
2372 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
2373 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002374 }
2375 }
2376 }
2377
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002378 private boolean isMockProvider(String provider) {
2379 synchronized (mLock) {
2380 return mMockProviders.containsKey(provider);
2381 }
2382 }
2383
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002384 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002385 // create a working copy of the incoming Location so that the service can modify it without
2386 // disturbing the caller's copy
2387 Location myLocation = new Location(location);
2388 String provider = myLocation.getProvider();
2389
2390 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2391 // bit if location did not come from a mock provider because passive/fused providers can
2392 // forward locations from mock providers, and should not grant them legitimacy in doing so.
2393 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
2394 myLocation.setIsFromMockProvider(true);
2395 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08002396
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002397 synchronized (mLock) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08002398 if (isAllowedByCurrentUserSettingsLocked(provider)) {
2399 if (!passive) {
2400 // notify passive provider of the new location
2401 mPassiveProvider.updateLocation(myLocation);
2402 }
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002403 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002404 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002405 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002406 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002407
Mike Lockwoode97ae402010-09-29 15:23:46 -04002408 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2409 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002410 public void onPackageDisappeared(String packageName, int reason) {
2411 // remove all receivers associated with this package name
2412 synchronized (mLock) {
2413 ArrayList<Receiver> deadReceivers = null;
2414
2415 for (Receiver receiver : mReceivers.values()) {
2416 if (receiver.mPackageName.equals(packageName)) {
2417 if (deadReceivers == null) {
2418 deadReceivers = new ArrayList<Receiver>();
2419 }
2420 deadReceivers.add(receiver);
2421 }
2422 }
2423
2424 // perform removal outside of mReceivers loop
2425 if (deadReceivers != null) {
2426 for (Receiver receiver : deadReceivers) {
2427 removeUpdatesLocked(receiver);
2428 }
2429 }
2430 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002431 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04002432 };
2433
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002434 // Geocoder
2435
Nick Pellye0fd6932012-07-11 10:26:13 -07002436 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04002437 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07002438 return mGeocodeProvider != null;
2439 }
2440
Nick Pellye0fd6932012-07-11 10:26:13 -07002441 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002442 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002443 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002444 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002445 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2446 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002447 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002448 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002449 }
2450
Mike Lockwooda55c3212009-04-15 11:10:11 -04002451
Nick Pellye0fd6932012-07-11 10:26:13 -07002452 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002453 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04002454 double lowerLeftLatitude, double lowerLeftLongitude,
2455 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002456 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002457
2458 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002459 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2460 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2461 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002462 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002463 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002464 }
2465
2466 // Mock Providers
2467
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002468 private boolean canCallerAccessMockLocation(String opPackageName) {
2469 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
2470 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002471 }
2472
Nick Pellye0fd6932012-07-11 10:26:13 -07002473 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002474 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
2475 if (!canCallerAccessMockLocation(opPackageName)) {
2476 return;
2477 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002478
Mike Lockwooda4903f22010-02-17 06:42:23 -05002479 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2480 throw new IllegalArgumentException("Cannot mock the passive location provider");
2481 }
2482
Mike Lockwood86328a92009-10-23 08:38:25 -04002483 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002484 synchronized (mLock) {
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002485 // remove the real provider if we are replacing GPS or network provider
2486 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07002487 || LocationManager.NETWORK_PROVIDER.equals(name)
2488 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002489 LocationProviderInterface p = mProvidersByName.get(name);
2490 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002491 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002492 }
2493 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09002494 addTestProviderLocked(name, properties);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002495 updateProvidersLocked();
2496 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002497 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002498 }
2499
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09002500 private void addTestProviderLocked(String name, ProviderProperties properties) {
2501 if (mProvidersByName.get(name) != null) {
2502 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2503 }
2504 MockProvider provider = new MockProvider(name, this, properties);
2505 addProviderLocked(provider);
2506 mMockProviders.put(name, provider);
2507 mLastLocation.put(name, null);
2508 mLastLocationCoarseInterval.put(name, null);
2509 }
2510
Nick Pellye0fd6932012-07-11 10:26:13 -07002511 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002512 public void removeTestProvider(String provider, String opPackageName) {
2513 if (!canCallerAccessMockLocation(opPackageName)) {
2514 return;
2515 }
2516
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002517 synchronized (mLock) {
Tom O'Neill07ee5d12014-03-03 17:48:35 -08002518
2519 // These methods can't be called after removing the test provider, so first make sure
Tom O'Neillfe6d3c52014-03-04 08:26:17 -08002520 // we don't leave anything dangling.
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002521 clearTestProviderEnabled(provider, opPackageName);
2522 clearTestProviderLocation(provider, opPackageName);
2523 clearTestProviderStatus(provider, opPackageName);
Tom O'Neill07ee5d12014-03-03 17:48:35 -08002524
You Kima6d0b6f2012-10-28 03:58:44 +09002525 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002526 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002527 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2528 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002529 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002530 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002531
2532 // reinstate real provider if available
2533 LocationProviderInterface realProvider = mRealProviders.get(provider);
2534 if (realProvider != null) {
2535 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002536 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002537 mLastLocation.put(provider, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002538 mLastLocationCoarseInterval.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002539 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002540 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002541 }
2542 }
2543
Nick Pellye0fd6932012-07-11 10:26:13 -07002544 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002545 public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
2546 if (!canCallerAccessMockLocation(opPackageName)) {
2547 return;
2548 }
2549
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002550 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002551 MockProvider mockProvider = mMockProviders.get(provider);
2552 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002553 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2554 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04002555 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2556 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002557 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04002558 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002559 }
2560 }
2561
Nick Pellye0fd6932012-07-11 10:26:13 -07002562 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002563 public void clearTestProviderLocation(String provider, String opPackageName) {
2564 if (!canCallerAccessMockLocation(opPackageName)) {
2565 return;
2566 }
2567
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002568 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002569 MockProvider mockProvider = mMockProviders.get(provider);
2570 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002571 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2572 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002573 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002574 }
2575 }
2576
Nick Pellye0fd6932012-07-11 10:26:13 -07002577 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002578 public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
2579 if (!canCallerAccessMockLocation(opPackageName)) {
2580 return;
2581 }
2582
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002583 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002584 MockProvider mockProvider = mMockProviders.get(provider);
2585 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002586 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2587 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002588 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002589 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002590 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002591 mEnabledProviders.add(provider);
2592 mDisabledProviders.remove(provider);
2593 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002594 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002595 mEnabledProviders.remove(provider);
2596 mDisabledProviders.add(provider);
2597 }
2598 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002599 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002600 }
2601 }
2602
Nick Pellye0fd6932012-07-11 10:26:13 -07002603 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002604 public void clearTestProviderEnabled(String provider, String opPackageName) {
2605 if (!canCallerAccessMockLocation(opPackageName)) {
2606 return;
2607 }
2608
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002609 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002610 MockProvider mockProvider = mMockProviders.get(provider);
2611 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002612 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2613 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002614 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002615 mEnabledProviders.remove(provider);
2616 mDisabledProviders.remove(provider);
2617 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002618 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002619 }
2620 }
2621
Nick Pellye0fd6932012-07-11 10:26:13 -07002622 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002623 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
2624 String opPackageName) {
2625 if (!canCallerAccessMockLocation(opPackageName)) {
2626 return;
2627 }
2628
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002629 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002630 MockProvider mockProvider = mMockProviders.get(provider);
2631 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002632 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2633 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002634 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002635 }
2636 }
2637
Nick Pellye0fd6932012-07-11 10:26:13 -07002638 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002639 public void clearTestProviderStatus(String provider, String opPackageName) {
2640 if (!canCallerAccessMockLocation(opPackageName)) {
2641 return;
2642 }
2643
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002644 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002645 MockProvider mockProvider = mMockProviders.get(provider);
2646 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002647 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2648 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002649 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002650 }
2651 }
2652
2653 private void log(String log) {
2654 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002655 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002656 }
2657 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002658
2659 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002660 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2661 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2662 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002663 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002664 + Binder.getCallingPid()
2665 + ", uid=" + Binder.getCallingUid());
2666 return;
2667 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002668
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002669 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002670 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002671 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002672 for (Receiver receiver : mReceivers.values()) {
2673 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002674 }
David Christie2ff96af2014-01-30 16:09:37 -08002675 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002676 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2677 pw.println(" " + entry.getKey() + ":");
2678 for (UpdateRecord record : entry.getValue()) {
2679 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002680 }
2681 }
David Christie2ff96af2014-01-30 16:09:37 -08002682 pw.println(" Historical Records by Provider:");
2683 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
2684 : mRequestStatistics.statistics.entrySet()) {
2685 PackageProviderKey key = entry.getKey();
2686 PackageStatistics stats = entry.getValue();
2687 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
2688 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002689 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002690 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2691 String provider = entry.getKey();
2692 Location location = entry.getValue();
2693 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002694 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002695
David Christie1b9b7b12013-04-15 15:31:11 -07002696 pw.println(" Last Known Locations Coarse Intervals:");
2697 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2698 String provider = entry.getKey();
2699 Location location = entry.getValue();
2700 pw.println(" " + provider + ": " + location);
2701 }
2702
Nick Pellye0fd6932012-07-11 10:26:13 -07002703 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002704
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002705 if (mEnabledProviders.size() > 0) {
2706 pw.println(" Enabled Providers:");
2707 for (String i : mEnabledProviders) {
2708 pw.println(" " + i);
2709 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002710
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002711 }
2712 if (mDisabledProviders.size() > 0) {
2713 pw.println(" Disabled Providers:");
2714 for (String i : mDisabledProviders) {
2715 pw.println(" " + i);
2716 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002717 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002718 pw.append(" ");
2719 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002720 if (mMockProviders.size() > 0) {
2721 pw.println(" Mock Providers:");
2722 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002723 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002724 }
2725 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002726
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002727 pw.append(" fudger: ");
2728 mLocationFudger.dump(fd, pw, args);
2729
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002730 if (args.length > 0 && "short".equals(args[0])) {
2731 return;
2732 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002733 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002734 pw.print(provider.getName() + " Internal State");
2735 if (provider instanceof LocationProviderProxy) {
2736 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2737 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002738 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002739 pw.println(":");
2740 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002741 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002742 }
2743 }
2744}