blob: c98f33e1e5b639c49caa538e41a670dea065d51b [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;
destradaaa4fa3b52014-07-09 10:46:39 -070024import com.android.server.location.ActivityRecognitionProxy;
destradaaea8a8a62014-06-23 18:19:03 -070025import com.android.server.location.FlpHardwareProvider;
26import com.android.server.location.FusedProxy;
27import com.android.server.location.GeocoderProxy;
28import com.android.server.location.GeofenceManager;
29import com.android.server.location.GeofenceProxy;
30import com.android.server.location.GpsLocationProvider;
31import com.android.server.location.GpsMeasurementsProvider;
destradaa4b3e3932014-07-21 18:01:47 -070032import com.android.server.location.GpsNavigationMessageProvider;
destradaaea8a8a62014-06-23 18:19:03 -070033import com.android.server.location.LocationBlacklist;
34import com.android.server.location.LocationFudger;
35import com.android.server.location.LocationProviderInterface;
36import com.android.server.location.LocationProviderProxy;
37import com.android.server.location.LocationRequestStatistics;
38import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
39import com.android.server.location.LocationRequestStatistics.PackageStatistics;
40import com.android.server.location.MockProvider;
41import com.android.server.location.PassiveProvider;
42
Dianne Hackborna06de0f2012-12-11 16:34:47 -080043import android.app.AppOpsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.app.PendingIntent;
Victoria Lease38389b62012-09-30 11:44:22 -070045import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.content.ContentResolver;
47import android.content.Context;
48import android.content.Intent;
Victoria Lease38389b62012-09-30 11:44:22 -070049import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070050import android.content.pm.ApplicationInfo;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050051import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.content.pm.PackageManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070053import android.content.pm.PackageManager.NameNotFoundException;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050054import android.content.pm.ResolveInfo;
55import android.content.pm.Signature;
Amith Yamasanib27528d2014-06-05 15:02:10 -070056import android.content.pm.UserInfo;
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;
Wei Liu5241a4c2015-05-11 14:00:36 -070064import android.location.IGpsGeofenceHardware;
destradaaea8a8a62014-06-23 18:19:03 -070065import android.location.IGpsMeasurementsListener;
destradaa4b3e3932014-07-21 18:01:47 -070066import android.location.IGpsNavigationMessageListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040068import android.location.IGpsStatusProvider;
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
Victoria Lease5cd731a2012-12-19 15:04:21 -0800153 // --- fields below are final after systemReady() ---
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;
160 private IGpsStatusProvider mGpsStatusProvider;
161 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;
destradaaea8a8a62014-06-23 18:19:03 -0700165 private GpsMeasurementsProvider mGpsMeasurementsProvider;
destradaa4b3e3932014-07-21 18:01:47 -0700166 private GpsNavigationMessageProvider mGpsNavigationMessageProvider;
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
171 private final Set<String> mEnabledProviders = new HashSet<String>();
172
173 // Set of providers that are explicitly disabled
174 private final Set<String> mDisabledProviders = new HashSet<String>();
175
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700176 // Mock (test) providers
177 private final HashMap<String, MockProvider> mMockProviders =
178 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700180 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400181 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700183 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500184 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700185 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400186
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700187 // real providers, saved here when mocked out
188 private final HashMap<String, LocationProviderInterface> mRealProviders =
189 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700191 // mapping from provider name to provider
192 private final HashMap<String, LocationProviderInterface> mProvidersByName =
193 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700195 // mapping from provider name to all its UpdateRecords
196 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
197 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700198
David Christie2ff96af2014-01-30 16:09:37 -0800199 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
200
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700201 // mapping from provider name to last known location
202 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203
David Christie1b9b7b12013-04-15 15:31:11 -0700204 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
205 // locations stored here are not fudged for coarse permissions.
206 private final HashMap<String, Location> mLastLocationCoarseInterval =
207 new HashMap<String, Location>();
208
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700209 // all providers that operate over proxy, for authorizing incoming location
210 private final ArrayList<LocationProviderProxy> mProxyProviders =
211 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212
Victoria Lease38389b62012-09-30 11:44:22 -0700213 // current active user on the device - other users are denied location data
214 private int mCurrentUserId = UserHandle.USER_OWNER;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700215 private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_OWNER };
Victoria Lease38389b62012-09-30 11:44:22 -0700216
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700217 public LocationManagerService(Context context) {
218 super();
219 mContext = context;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800220 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800221
Svet Ganovadc1cf42015-06-15 16:36:24 -0700222 // Let the package manager query which are the default location
223 // providers as they get certain permissions granted by default.
224 PackageManagerInternal packageManagerInternal = LocalServices.getService(
225 PackageManagerInternal.class);
226 packageManagerInternal.setLocationPackagesProvider(
227 new PackageManagerInternal.PackagesProvider() {
228 @Override
229 public String[] getPackages(int userId) {
230 return mContext.getResources().getStringArray(
231 com.android.internal.R.array.config_locationProviderPackageNames);
232 }
233 });
234
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700235 if (D) Log.d(TAG, "Constructed");
236
237 // most startup is deferred until systemReady()
238 }
239
Svetoslav Ganova0027152013-06-25 14:59:53 -0700240 public void systemRunning() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700241 synchronized (mLock) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800242 if (D) Log.d(TAG, "systemReady()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700243
Victoria Lease5cd731a2012-12-19 15:04:21 -0800244 // fetch package manager
245 mPackageManager = mContext.getPackageManager();
246
Victoria Lease0aa28602013-05-29 15:28:26 -0700247 // fetch power manager
248 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800249
250 // prepare worker thread
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700251 mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
Victoria Lease5cd731a2012-12-19 15:04:21 -0800252
253 // prepare mLocationHandler's dependents
254 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
255 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
256 mBlacklist.init();
257 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
258
Dianne Hackbornc2293022013-02-06 23:14:49 -0800259 // Monitor for app ops mode changes.
Dianne Hackborn9bb0ee92013-09-22 12:31:38 -0700260 AppOpsManager.OnOpChangedListener callback
261 = new AppOpsManager.OnOpChangedInternalListener() {
262 public void onOpChanged(int op, String packageName) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800263 synchronized (mLock) {
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700264 for (Receiver receiver : mReceivers.values()) {
265 receiver.updateMonitoring(true);
266 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800267 applyAllProviderRequirementsLocked();
268 }
269 }
270 };
271 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
272
Amith Yamasanib27528d2014-06-05 15:02:10 -0700273 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
274 updateUserProfiles(mCurrentUserId);
275
Victoria Lease5cd731a2012-12-19 15:04:21 -0800276 // prepare providers
277 loadProvidersLocked();
278 updateProvidersLocked();
279 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700280
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700281 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700282 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700283 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700284 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800285 @Override
286 public void onChange(boolean selfChange) {
287 synchronized (mLock) {
288 updateProvidersLocked();
289 }
290 }
291 }, UserHandle.USER_ALL);
292 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700293
Victoria Lease38389b62012-09-30 11:44:22 -0700294 // listen for user change
295 IntentFilter intentFilter = new IntentFilter();
296 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700297 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
298 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
Victoria Lease38389b62012-09-30 11:44:22 -0700299
300 mContext.registerReceiverAsUser(new BroadcastReceiver() {
301 @Override
302 public void onReceive(Context context, Intent intent) {
303 String action = intent.getAction();
304 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
305 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
Amith Yamasanib27528d2014-06-05 15:02:10 -0700306 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
307 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
308 updateUserProfiles(mCurrentUserId);
Victoria Lease38389b62012-09-30 11:44:22 -0700309 }
310 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800311 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700312 }
313
Amith Yamasanib27528d2014-06-05 15:02:10 -0700314 /**
315 * Makes a list of userids that are related to the current user. This is
316 * relevant when using managed profiles. Otherwise the list only contains
317 * the current user.
318 *
319 * @param currentUserId the current user, who might have an alter-ego.
320 */
321 void updateUserProfiles(int currentUserId) {
322 List<UserInfo> profiles = mUserManager.getProfiles(currentUserId);
323 synchronized (mLock) {
324 mCurrentUserProfiles = new int[profiles.size()];
325 for (int i = 0; i < mCurrentUserProfiles.length; i++) {
326 mCurrentUserProfiles[i] = profiles.get(i).id;
327 }
328 }
329 }
330
331 /**
332 * Checks if the specified userId matches any of the current foreground
333 * users stored in mCurrentUserProfiles.
334 */
335 private boolean isCurrentProfile(int userId) {
336 synchronized (mLock) {
337 for (int i = 0; i < mCurrentUserProfiles.length; i++) {
338 if (mCurrentUserProfiles[i] == userId) {
339 return true;
340 }
341 }
342 return false;
343 }
344 }
345
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500346 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
347 PackageManager pm = mContext.getPackageManager();
348 String systemPackageName = mContext.getPackageName();
349 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
350
351 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
352 new Intent(FUSED_LOCATION_SERVICE_ACTION),
353 PackageManager.GET_META_DATA, mCurrentUserId);
354 for (ResolveInfo rInfo : rInfos) {
355 String packageName = rInfo.serviceInfo.packageName;
356
357 // Check that the signature is in the list of supported sigs. If it's not in
358 // this list the standard provider binding logic won't bind to it.
359 try {
360 PackageInfo pInfo;
361 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
362 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
363 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
364 ", but has wrong signature, ignoring");
365 continue;
366 }
367 } catch (NameNotFoundException e) {
368 Log.e(TAG, "missing package: " + packageName);
369 continue;
370 }
371
372 // Get the version info
373 if (rInfo.serviceInfo.metaData == null) {
374 Log.w(TAG, "Found fused provider without metadata: " + packageName);
375 continue;
376 }
377
378 int version = rInfo.serviceInfo.metaData.getInt(
379 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
380 if (version == 0) {
381 // This should be the fallback fused location provider.
382
383 // Make sure it's in the system partition.
384 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
385 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
386 continue;
387 }
388
389 // Check that the fallback is signed the same as the OS
390 // as a proxy for coreApp="true"
391 if (pm.checkSignatures(systemPackageName, packageName)
392 != PackageManager.SIGNATURE_MATCH) {
393 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
394 + packageName);
395 continue;
396 }
397
398 // Found a valid fallback.
399 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
400 return;
401 } else {
402 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
403 }
404 }
405
406 throw new IllegalStateException("Unable to find a fused location provider that is in the "
407 + "system partition with version 0 and signed with the platform certificate. "
408 + "Such a package is needed to provide a default fused location provider in the "
409 + "event that no other fused location provider has been installed or is currently "
410 + "available. For example, coreOnly boot mode when decrypting the data "
411 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
412 }
413
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700414 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700415 // create a passive location provider, which is always enabled
416 PassiveProvider passiveProvider = new PassiveProvider(this);
417 addProviderLocked(passiveProvider);
418 mEnabledProviders.add(passiveProvider.getName());
419 mPassiveProvider = passiveProvider;
420
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700421 if (GpsLocationProvider.isSupported()) {
Wei Liu5241a4c2015-05-11 14:00:36 -0700422 // Create a gps location provider
423 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
424 mLocationHandler.getLooper());
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700425 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
426 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
427 addProviderLocked(gpsProvider);
428 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
Wei Liu5241a4c2015-05-11 14:00:36 -0700429 mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider();
430 mGpsNavigationMessageProvider = gpsProvider.getGpsNavigationMessageProvider();
431 mGpsGeofenceProxy = gpsProvider.getGpsGeofenceProxy();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700432 }
433
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700434 /*
435 Load package name(s) containing location provider support.
436 These packages can contain services implementing location providers:
437 Geocoder Provider, Network Location Provider, and
438 Fused Location Provider. They will each be searched for
439 service components implementing these providers.
440 The location framework also has support for installation
441 of new location providers at run-time. The new package does not
442 have to be explicitly listed here, however it must have a signature
443 that matches the signature of at least one package on this list.
444 */
445 Resources resources = mContext.getResources();
446 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500447 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700448 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500449 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
450 Arrays.toString(pkgs));
451 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
452
453 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700454
455 // bind to network provider
456 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
457 mContext,
458 LocationManager.NETWORK_PROVIDER,
459 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700460 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
461 com.android.internal.R.string.config_networkLocationProviderPackageName,
462 com.android.internal.R.array.config_locationProviderPackageNames,
463 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700464 if (networkProvider != null) {
465 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
466 mProxyProviders.add(networkProvider);
467 addProviderLocked(networkProvider);
468 } else {
469 Slog.w(TAG, "no network location provider found");
470 }
471
472 // bind to fused provider
473 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
474 mContext,
475 LocationManager.FUSED_PROVIDER,
476 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700477 com.android.internal.R.bool.config_enableFusedLocationOverlay,
478 com.android.internal.R.string.config_fusedLocationProviderPackageName,
479 com.android.internal.R.array.config_locationProviderPackageNames,
480 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700481 if (fusedLocationProvider != null) {
482 addProviderLocked(fusedLocationProvider);
483 mProxyProviders.add(fusedLocationProvider);
484 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700485 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700486 } else {
487 Slog.e(TAG, "no fused location provider found",
488 new IllegalStateException("Location service needs a fused location provider"));
489 }
490
491 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700492 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
493 com.android.internal.R.bool.config_enableGeocoderOverlay,
494 com.android.internal.R.string.config_geocoderProviderPackageName,
495 com.android.internal.R.array.config_locationProviderPackageNames,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800496 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700497 if (mGeocodeProvider == null) {
498 Slog.e(TAG, "no geocoder provider found");
499 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700500
destradaaa4fa3b52014-07-09 10:46:39 -0700501 // bind to fused hardware provider if supported
destradaabeea4422014-07-30 18:17:21 -0700502 // in devices without support, requesting an instance of FlpHardwareProvider will raise an
503 // exception, so make sure we only do that when supported
504 FlpHardwareProvider flpHardwareProvider;
destradaa5ce66d82014-05-28 18:24:08 -0700505 if (FlpHardwareProvider.isSupported()) {
destradaabeea4422014-07-30 18:17:21 -0700506 flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
destradaaf9a274c2014-07-25 15:11:56 -0700507 FusedProxy fusedProxy = FusedProxy.createAndBind(
508 mContext,
509 mLocationHandler,
510 flpHardwareProvider.getLocationHardware(),
511 com.android.internal.R.bool.config_enableHardwareFlpOverlay,
512 com.android.internal.R.string.config_hardwareFlpPackageName,
513 com.android.internal.R.array.config_locationProviderPackageNames);
514 if (fusedProxy == null) {
515 Slog.e(TAG, "Unable to bind FusedProxy.");
516 }
destradaacfbdcd22014-04-30 11:29:11 -0700517 } else {
destradaabeea4422014-07-30 18:17:21 -0700518 flpHardwareProvider = null;
destradaaf9a274c2014-07-25 15:11:56 -0700519 Slog.e(TAG, "FLP HAL not supported");
520 }
521
522 // bind to geofence provider
523 GeofenceProxy provider = GeofenceProxy.createAndBind(
524 mContext,com.android.internal.R.bool.config_enableGeofenceOverlay,
525 com.android.internal.R.string.config_geofenceProviderPackageName,
526 com.android.internal.R.array.config_locationProviderPackageNames,
527 mLocationHandler,
Wei Liu5241a4c2015-05-11 14:00:36 -0700528 mGpsGeofenceProxy,
destradaabeea4422014-07-30 18:17:21 -0700529 flpHardwareProvider != null ? flpHardwareProvider.getGeofenceHardware() : null);
destradaaf9a274c2014-07-25 15:11:56 -0700530 if (provider == null) {
531 Slog.e(TAG, "Unable to bind FLP Geofence proxy.");
destradaa0682809a2013-08-12 18:50:30 -0700532 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900533
destradaaa4fa3b52014-07-09 10:46:39 -0700534 // bind to the hardware activity recognition if supported
535 if (ActivityRecognitionHardware.isSupported()) {
536 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
537 mContext,
538 mLocationHandler,
539 ActivityRecognitionHardware.getInstance(mContext),
540 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
541 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
542 com.android.internal.R.array.config_locationProviderPackageNames);
543
544 if (proxy == null) {
545 Slog.e(TAG, "Unable to bind ActivityRecognitionProxy.");
546 }
547 } else {
548 Slog.e(TAG, "Hardware Activity-Recognition not supported.");
549 }
550
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900551 String[] testProviderStrings = resources.getStringArray(
552 com.android.internal.R.array.config_testLocationProviders);
553 for (String testProviderString : testProviderStrings) {
554 String fragments[] = testProviderString.split(",");
555 String name = fragments[0].trim();
556 if (mProvidersByName.get(name) != null) {
557 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
558 }
559 ProviderProperties properties = new ProviderProperties(
560 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
561 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
562 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
563 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
564 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
565 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
566 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
567 Integer.parseInt(fragments[8]) /* powerRequirement */,
568 Integer.parseInt(fragments[9]) /* accuracy */);
569 addTestProviderLocked(name, properties);
570 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700571 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700574 * Called when the device's active user changes.
575 * @param userId the new active user's UserId
576 */
577 private void switchUser(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800578 if (mCurrentUserId == userId) {
579 return;
580 }
Victoria Lease83762d22012-10-03 13:51:17 -0700581 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800582 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700583 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700584 mLastLocation.clear();
David Christie1b9b7b12013-04-15 15:31:11 -0700585 mLastLocationCoarseInterval.clear();
Victoria Leaseb711d572012-10-02 13:14:11 -0700586 for (LocationProviderInterface p : mProviders) {
Amith Yamasanib27528d2014-06-05 15:02:10 -0700587 updateProviderListenersLocked(p.getName(), false);
Victoria Leaseb711d572012-10-02 13:14:11 -0700588 }
Victoria Lease38389b62012-09-30 11:44:22 -0700589 mCurrentUserId = userId;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700590 updateUserProfiles(userId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700591 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700592 }
593 }
594
595 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
597 * location updates.
598 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700599 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700600 final int mUid; // uid of receiver
601 final int mPid; // pid of receiver
602 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700603 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700604
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605 final ILocationListener mListener;
606 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -0700607 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
David Christie40e57822013-07-30 11:36:48 -0700608 final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700610
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400611 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700612
David Christie0b837452013-07-29 16:02:13 -0700613 // True if app ops has started monitoring this receiver for locations.
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700614 boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -0700615 // True if app ops has started monitoring this receiver for high power (gps) locations.
616 boolean mOpHighPowerMonitoring;
Mike Lockwood48f17512009-04-23 09:12:08 -0700617 int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -0700618 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700620 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -0700621 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700624 if (listener != null) {
625 mKey = listener.asBinder();
626 } else {
627 mKey = intent;
628 }
Victoria Lease37425c32012-10-16 16:08:48 -0700629 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700630 mUid = uid;
631 mPid = pid;
632 mPackageName = packageName;
David Christie82edc9b2013-07-19 11:31:42 -0700633 if (workSource != null && workSource.size() <= 0) {
634 workSource = null;
635 }
636 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -0700637 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -0700638
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700639 updateMonitoring(true);
640
Victoria Lease0aa28602013-05-29 15:28:26 -0700641 // construct/configure wakelock
642 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -0700643 if (workSource == null) {
644 workSource = new WorkSource(mUid, mPackageName);
645 }
646 mWakeLock.setWorkSource(workSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 }
648
649 @Override
650 public boolean equals(Object otherObj) {
651 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700652 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 }
654 return false;
655 }
656
657 @Override
658 public int hashCode() {
659 return mKey.hashCode();
660 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400661
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 @Override
663 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700664 StringBuilder s = new StringBuilder();
665 s.append("Reciever[");
666 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700668 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800669 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700670 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700672 for (String p : mUpdateRecords.keySet()) {
673 s.append(" ").append(mUpdateRecords.get(p).toString());
674 }
675 s.append("]");
676 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 }
678
David Christie15b31912013-08-13 15:54:32 -0700679 /**
680 * Update AppOp monitoring for this receiver.
681 *
682 * @param allow If true receiver is currently active, if false it's been removed.
683 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700684 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -0700685 if (mHideFromAppOps) {
686 return;
687 }
688
David Christie15b31912013-08-13 15:54:32 -0700689 boolean requestingLocation = false;
690 boolean requestingHighPowerLocation = false;
691 if (allow) {
692 // See if receiver has any enabled update records. Also note if any update records
693 // are high power (has a high power provider with an interval under a threshold).
694 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
695 if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) {
696 requestingLocation = true;
697 LocationProviderInterface locationProvider
David Christie2ff96af2014-01-30 16:09:37 -0800698 = mProvidersByName.get(updateRecord.mProvider);
David Christie15b31912013-08-13 15:54:32 -0700699 ProviderProperties properties = locationProvider != null
700 ? locationProvider.getProperties() : null;
701 if (properties != null
702 && properties.mPowerRequirement == Criteria.POWER_HIGH
703 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
704 requestingHighPowerLocation = true;
705 break;
706 }
707 }
708 }
709 }
710
David Christie0b837452013-07-29 16:02:13 -0700711 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -0700712 mOpMonitoring = updateMonitoring(
713 requestingLocation,
714 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700715 AppOpsManager.OP_MONITOR_LOCATION);
716
717 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -0700718 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -0700719 mOpHighPowerMonitoring = updateMonitoring(
720 requestingHighPowerLocation,
721 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700722 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -0700723 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -0700724 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -0700725 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
726 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
727 }
David Christie0b837452013-07-29 16:02:13 -0700728 }
729
730 /**
731 * Update AppOps monitoring for a single location request and op type.
732 *
733 * @param allowMonitoring True if monitoring is allowed for this request/op.
734 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
735 * @param op AppOps code for the op to update.
736 * @return True if monitoring is on for this request/op after updating.
737 */
738 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
739 int op) {
740 if (!currentlyMonitoring) {
741 if (allowMonitoring) {
742 return mAppOps.startOpNoThrow(op, mUid, mPackageName)
743 == AppOpsManager.MODE_ALLOWED;
744 }
745 } else {
746 if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
747 != AppOpsManager.MODE_ALLOWED) {
748 mAppOps.finishOp(op, mUid, mPackageName);
749 return false;
750 }
751 }
752
753 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700754 }
755
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 public boolean isListener() {
757 return mListener != null;
758 }
759
760 public boolean isPendingIntent() {
761 return mPendingIntent != null;
762 }
763
764 public ILocationListener getListener() {
765 if (mListener != null) {
766 return mListener;
767 }
768 throw new IllegalStateException("Request for non-existent listener");
769 }
770
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
772 if (mListener != null) {
773 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700774 synchronized (this) {
775 // synchronize to ensure incrementPendingBroadcastsLocked()
776 // is called before decrementPendingBroadcasts()
777 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700778 // call this after broadcasting so we do not increment
779 // if we throw an exeption.
780 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700781 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782 } catch (RemoteException e) {
783 return false;
784 }
785 } else {
786 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800787 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
789 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700790 synchronized (this) {
791 // synchronize to ensure incrementPendingBroadcastsLocked()
792 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700793 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700794 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700795 // call this after broadcasting so we do not increment
796 // if we throw an exeption.
797 incrementPendingBroadcastsLocked();
798 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 } catch (PendingIntent.CanceledException e) {
800 return false;
801 }
802 }
803 return true;
804 }
805
806 public boolean callLocationChangedLocked(Location location) {
807 if (mListener != null) {
808 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700809 synchronized (this) {
810 // synchronize to ensure incrementPendingBroadcastsLocked()
811 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800812 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700813 // call this after broadcasting so we do not increment
814 // if we throw an exeption.
815 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700816 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 } catch (RemoteException e) {
818 return false;
819 }
820 } else {
821 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800822 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700824 synchronized (this) {
825 // synchronize to ensure incrementPendingBroadcastsLocked()
826 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700827 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700828 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700829 // call this after broadcasting so we do not increment
830 // if we throw an exeption.
831 incrementPendingBroadcastsLocked();
832 }
833 } catch (PendingIntent.CanceledException e) {
834 return false;
835 }
836 }
837 return true;
838 }
839
840 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -0700841 // First update AppOp monitoring.
842 // An app may get/lose location access as providers are enabled/disabled.
843 updateMonitoring(true);
844
Mike Lockwood48f17512009-04-23 09:12:08 -0700845 if (mListener != null) {
846 try {
847 synchronized (this) {
848 // synchronize to ensure incrementPendingBroadcastsLocked()
849 // is called before decrementPendingBroadcasts()
850 if (enabled) {
851 mListener.onProviderEnabled(provider);
852 } else {
853 mListener.onProviderDisabled(provider);
854 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700855 // call this after broadcasting so we do not increment
856 // if we throw an exeption.
857 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700858 }
859 } catch (RemoteException e) {
860 return false;
861 }
862 } else {
863 Intent providerIntent = new Intent();
864 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
865 try {
866 synchronized (this) {
867 // synchronize to ensure incrementPendingBroadcastsLocked()
868 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700869 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700870 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700871 // call this after broadcasting so we do not increment
872 // if we throw an exeption.
873 incrementPendingBroadcastsLocked();
874 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 } catch (PendingIntent.CanceledException e) {
876 return false;
877 }
878 }
879 return true;
880 }
881
Nick Pellyf1be6862012-05-15 10:53:42 -0700882 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700884 if (D) Log.d(TAG, "Location listener died");
885
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400886 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887 removeUpdatesLocked(this);
888 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700889 synchronized (this) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700890 clearPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700891 }
892 }
893
Nick Pellye0fd6932012-07-11 10:26:13 -0700894 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700895 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
896 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400897 synchronized (this) {
898 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700899 }
900 }
901
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400902 // this must be called while synchronized by caller in a synchronized block
903 // containing the sending of the broadcaset
904 private void incrementPendingBroadcastsLocked() {
905 if (mPendingBroadcasts++ == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700906 mWakeLock.acquire();
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400907 }
908 }
909
910 private void decrementPendingBroadcastsLocked() {
911 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700912 if (mWakeLock.isHeld()) {
913 mWakeLock.release();
914 }
915 }
916 }
917
918 public void clearPendingBroadcastsLocked() {
919 if (mPendingBroadcasts > 0) {
920 mPendingBroadcasts = 0;
921 if (mWakeLock.isHeld()) {
922 mWakeLock.release();
923 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700924 }
925 }
926 }
927
Nick Pellye0fd6932012-07-11 10:26:13 -0700928 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700929 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700930 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -0400931 //the receiver list if it is not found. If it is not found then the
932 //LocationListener was removed when it had a pending broadcast and should
933 //not be added back.
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700934 synchronized (mLock) {
935 IBinder binder = listener.asBinder();
936 Receiver receiver = mReceivers.get(binder);
937 if (receiver != null) {
938 synchronized (receiver) {
939 // so wakelock calls will succeed
940 long identity = Binder.clearCallingIdentity();
941 receiver.decrementPendingBroadcastsLocked();
942 Binder.restoreCallingIdentity(identity);
David Christie2ff96af2014-01-30 16:09:37 -0800943 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700944 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 }
946 }
947
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700948 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400949 mProviders.add(provider);
950 mProvidersByName.put(provider.getName(), provider);
951 }
952
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700953 private void removeProviderLocked(LocationProviderInterface provider) {
954 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400955 mProviders.remove(provider);
956 mProvidersByName.remove(provider.getName());
957 }
958
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800959 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800960 * Returns "true" if access to the specified location provider is allowed by the current
961 * user's settings. Access to all location providers is forbidden to non-location-provider
962 * processes belonging to background users.
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800963 *
964 * @param provider the name of the location provider
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800965 * @return
966 */
Victoria Lease09eeaec2013-02-05 11:34:13 -0800967 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 if (mEnabledProviders.contains(provider)) {
969 return true;
970 }
971 if (mDisabledProviders.contains(provider)) {
972 return false;
973 }
974 // Use system settings
975 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976
Victoria Leaseb711d572012-10-02 13:14:11 -0700977 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978 }
979
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700980 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800981 * Returns "true" if access to the specified location provider is allowed by the specified
982 * user's settings. Access to all location providers is forbidden to non-location-provider
983 * processes belonging to background users.
984 *
985 * @param provider the name of the location provider
986 * @param uid the requestor's UID
987 * @return
988 */
989 private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
Amith Yamasanib27528d2014-06-05 15:02:10 -0700990 if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -0800991 return false;
992 }
993 return isAllowedByCurrentUserSettingsLocked(provider);
994 }
995
996 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700997 * Returns the permission string associated with the specified resolution level.
998 *
999 * @param resolutionLevel the resolution level
1000 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001001 */
Victoria Lease37425c32012-10-16 16:08:48 -07001002 private String getResolutionPermission(int resolutionLevel) {
1003 switch (resolutionLevel) {
1004 case RESOLUTION_LEVEL_FINE:
1005 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1006 case RESOLUTION_LEVEL_COARSE:
1007 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1008 default:
1009 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001011 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001012
Victoria Leaseda479c52012-10-15 15:24:16 -07001013 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001014 * Returns the resolution level allowed to the given PID/UID pair.
1015 *
1016 * @param pid the PID
1017 * @param uid the UID
1018 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -07001019 */
Victoria Lease37425c32012-10-16 16:08:48 -07001020 private int getAllowedResolutionLevel(int pid, int uid) {
1021 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
1022 pid, uid) == PackageManager.PERMISSION_GRANTED) {
1023 return RESOLUTION_LEVEL_FINE;
1024 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
1025 pid, uid) == PackageManager.PERMISSION_GRANTED) {
1026 return RESOLUTION_LEVEL_COARSE;
1027 } else {
1028 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001029 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001030 }
1031
1032 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001033 * Returns the resolution level allowed to the caller
1034 *
1035 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -07001036 */
Victoria Lease37425c32012-10-16 16:08:48 -07001037 private int getCallerAllowedResolutionLevel() {
1038 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1039 }
1040
1041 /**
1042 * Throw SecurityException if specified resolution level is insufficient to use geofences.
1043 *
1044 * @param allowedResolutionLevel resolution level allowed to caller
1045 */
1046 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1047 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001048 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1049 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 }
1051
Victoria Lease37425c32012-10-16 16:08:48 -07001052 /**
1053 * Return the minimum resolution level required to use the specified location provider.
1054 *
1055 * @param provider the name of the location provider
1056 * @return minimum resolution level required for provider
1057 */
1058 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001059 if (LocationManager.GPS_PROVIDER.equals(provider) ||
1060 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1061 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001062 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -07001063 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1064 LocationManager.FUSED_PROVIDER.equals(provider)) {
1065 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001066 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001067 } else {
1068 // mock providers
1069 LocationProviderInterface lp = mMockProviders.get(provider);
1070 if (lp != null) {
1071 ProviderProperties properties = lp.getProperties();
1072 if (properties != null) {
1073 if (properties.mRequiresSatellite) {
1074 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001075 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001076 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1077 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001078 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001079 }
1080 }
1081 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001082 }
Victoria Lease37425c32012-10-16 16:08:48 -07001083 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001084 }
1085
Victoria Lease37425c32012-10-16 16:08:48 -07001086 /**
1087 * Throw SecurityException if specified resolution level is insufficient to use the named
1088 * location provider.
1089 *
1090 * @param allowedResolutionLevel resolution level allowed to caller
1091 * @param providerName the name of the location provider
1092 */
1093 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1094 String providerName) {
1095 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1096 if (allowedResolutionLevel < requiredResolutionLevel) {
1097 switch (requiredResolutionLevel) {
1098 case RESOLUTION_LEVEL_FINE:
1099 throw new SecurityException("\"" + providerName + "\" location provider " +
1100 "requires ACCESS_FINE_LOCATION permission.");
1101 case RESOLUTION_LEVEL_COARSE:
1102 throw new SecurityException("\"" + providerName + "\" location provider " +
1103 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1104 default:
1105 throw new SecurityException("Insufficient permission for \"" + providerName +
1106 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001107 }
1108 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001109 }
1110
David Christie82edc9b2013-07-19 11:31:42 -07001111 /**
1112 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
1113 * for battery).
1114 */
David Christie40e57822013-07-30 11:36:48 -07001115 private void checkDeviceStatsAllowed() {
David Christie82edc9b2013-07-19 11:31:42 -07001116 mContext.enforceCallingOrSelfPermission(
1117 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
1118 }
1119
David Christie40e57822013-07-30 11:36:48 -07001120 private void checkUpdateAppOpsAllowed() {
1121 mContext.enforceCallingOrSelfPermission(
1122 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
1123 }
1124
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001125 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001126 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1127 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001128 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001129 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001130 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001131 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001132 }
1133 return -1;
1134 }
1135
1136 boolean reportLocationAccessNoThrow(int uid, String packageName, int allowedResolutionLevel) {
1137 int op = resolutionLevelToOp(allowedResolutionLevel);
1138 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001139 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1140 return false;
1141 }
1142 }
1143 return true;
1144 }
1145
1146 boolean checkLocationAccess(int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001147 int op = resolutionLevelToOp(allowedResolutionLevel);
1148 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001149 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1150 return false;
1151 }
1152 }
1153 return true;
1154 }
1155
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001156 /**
1157 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -07001158 * fused, also including ones that are not permitted to
1159 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001160 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001161 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001163 ArrayList<String> out;
1164 synchronized (mLock) {
1165 out = new ArrayList<String>(mProviders.size());
1166 for (LocationProviderInterface provider : mProviders) {
1167 String name = provider.getName();
1168 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001169 continue;
1170 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001171 out.add(name);
1172 }
1173 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001174
1175 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 return out;
1177 }
1178
Mike Lockwood03ca2162010-04-01 08:10:09 -07001179 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001180 * Return all providers by name, that match criteria and are optionally
1181 * enabled.
1182 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001183 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001184 @Override
1185 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001186 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001187 ArrayList<String> out;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001188 int uid = Binder.getCallingUid();;
Victoria Lease269518e2012-10-29 08:25:39 -07001189 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001190 try {
1191 synchronized (mLock) {
1192 out = new ArrayList<String>(mProviders.size());
1193 for (LocationProviderInterface provider : mProviders) {
1194 String name = provider.getName();
1195 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001196 continue;
1197 }
Victoria Lease37425c32012-10-16 16:08:48 -07001198 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001199 if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001200 continue;
1201 }
1202 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
1203 name, provider.getProperties(), criteria)) {
1204 continue;
1205 }
1206 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001207 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001208 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001209 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001210 } finally {
1211 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001212 }
1213
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001214 if (D) Log.d(TAG, "getProviders()=" + out);
1215 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001216 }
1217
1218 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001219 * Return the name of the best provider given a Criteria object.
1220 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001221 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001222 * has been deprecated as well. So this method now uses
1223 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001224 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001225 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001226 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001227 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001228
1229 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001230 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001231 result = pickBest(providers);
1232 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1233 return result;
1234 }
1235 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001236 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001237 result = pickBest(providers);
1238 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1239 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001240 }
1241
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001242 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001243 return null;
1244 }
1245
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001246 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -07001247 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001248 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -07001249 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1250 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001251 } else {
1252 return providers.get(0);
1253 }
1254 }
1255
Nick Pellye0fd6932012-07-11 10:26:13 -07001256 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001257 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1258 LocationProviderInterface p = mProvidersByName.get(provider);
1259 if (p == null) {
1260 throw new IllegalArgumentException("provider=" + provider);
1261 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001262
1263 boolean result = LocationProvider.propertiesMeetCriteria(
1264 p.getName(), p.getProperties(), criteria);
1265 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1266 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001267 }
1268
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001270 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001271 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001272 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 boolean isEnabled = p.isEnabled();
1274 String name = p.getName();
Victoria Lease09eeaec2013-02-05 11:34:13 -08001275 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276 if (isEnabled && !shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001277 updateProviderListenersLocked(name, false);
David Christieb084fef2013-12-18 14:33:57 -08001278 // If any provider has been disabled, clear all last locations for all providers.
1279 // This is to be on the safe side in case a provider has location derived from
1280 // this disabled provider.
1281 mLastLocation.clear();
1282 mLastLocationCoarseInterval.clear();
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001283 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001284 } else if (!isEnabled && shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001285 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001286 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001287 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001288 }
1289 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001290 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1291 UserHandle.ALL);
Tom O'Neill40a86c22013-09-03 18:05:13 -07001292 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1293 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001294 }
1295 }
1296
Amith Yamasanib27528d2014-06-05 15:02:10 -07001297 private void updateProviderListenersLocked(String provider, boolean enabled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001298 int listeners = 0;
1299
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001300 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001301 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001302
1303 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001305 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1306 if (records != null) {
1307 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001308 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309 UpdateRecord record = records.get(i);
Amith Yamasanib27528d2014-06-05 15:02:10 -07001310 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001311 // Sends a notification message to the receiver
1312 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1313 if (deadReceivers == null) {
1314 deadReceivers = new ArrayList<Receiver>();
1315 }
1316 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001318 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001319 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 }
1321 }
1322
1323 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001324 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001325 removeUpdatesLocked(deadReceivers.get(i));
1326 }
1327 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001329 if (enabled) {
1330 p.enable();
1331 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001332 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333 }
1334 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001335 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001336 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001337 }
1338
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001339 private void applyRequirementsLocked(String provider) {
1340 LocationProviderInterface p = mProvidersByName.get(provider);
1341 if (p == null) return;
1342
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001343 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001344 WorkSource worksource = new WorkSource();
1345 ProviderRequest providerRequest = new ProviderRequest();
1346
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001347 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001348 for (UpdateRecord record : records) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001349 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001350 if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName,
1351 record.mReceiver.mAllowedResolutionLevel)) {
1352 LocationRequest locationRequest = record.mRequest;
1353 providerRequest.locationRequests.add(locationRequest);
1354 if (locationRequest.getInterval() < providerRequest.interval) {
1355 providerRequest.reportLocation = true;
1356 providerRequest.interval = locationRequest.getInterval();
1357 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001358 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001359 }
1360 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001361
1362 if (providerRequest.reportLocation) {
1363 // calculate who to blame for power
1364 // This is somewhat arbitrary. We pick a threshold interval
1365 // that is slightly higher that the minimum interval, and
1366 // spread the blame across all applications with a request
1367 // under that threshold.
1368 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1369 for (UpdateRecord record : records) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001370 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001371 LocationRequest locationRequest = record.mRequest;
1372 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07001373 if (record.mReceiver.mWorkSource != null
1374 && record.mReceiver.mWorkSource.size() > 0
1375 && record.mReceiver.mWorkSource.getName(0) != null) {
David Christie82edc9b2013-07-19 11:31:42 -07001376 // Assign blame to another work source.
David Christiee55c9682013-08-22 10:10:34 -07001377 // Can only assign blame if the WorkSource contains names.
David Christie82edc9b2013-07-19 11:31:42 -07001378 worksource.add(record.mReceiver.mWorkSource);
1379 } else {
1380 // Assign blame to caller.
1381 worksource.add(
1382 record.mReceiver.mUid,
1383 record.mReceiver.mPackageName);
1384 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001385 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001386 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001387 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001388 }
1389 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001390
1391 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1392 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001393 }
1394
1395 private class UpdateRecord {
1396 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001397 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001399 Location mLastFixBroadcast;
1400 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401
1402 /**
1403 * Note: must be constructed with lock held.
1404 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001405 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001406 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001407 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001409
1410 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1411 if (records == null) {
1412 records = new ArrayList<UpdateRecord>();
1413 mRecordsByProvider.put(provider, records);
1414 }
1415 if (!records.contains(this)) {
1416 records.add(this);
1417 }
David Christie2ff96af2014-01-30 16:09:37 -08001418
1419 // Update statistics for historical location requests by package/provider
1420 mRequestStatistics.startRequesting(
1421 mReceiver.mPackageName, provider, request.getInterval());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 }
1423
1424 /**
David Christie2ff96af2014-01-30 16:09:37 -08001425 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001426 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001427 void disposeLocked(boolean removeReceiver) {
David Christie2ff96af2014-01-30 16:09:37 -08001428 mRequestStatistics.stopRequesting(mReceiver.mPackageName, mProvider);
1429
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001430 // remove from mRecordsByProvider
1431 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1432 if (globalRecords != null) {
1433 globalRecords.remove(this);
1434 }
1435
1436 if (!removeReceiver) return; // the caller will handle the rest
1437
1438 // remove from Receiver#mUpdateRecords
1439 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1440 if (receiverRecords != null) {
1441 receiverRecords.remove(this.mProvider);
1442
1443 // and also remove the Receiver if it has no more update records
1444 if (removeReceiver && receiverRecords.size() == 0) {
1445 removeUpdatesLocked(mReceiver);
1446 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001447 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 }
1449
1450 @Override
1451 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001452 StringBuilder s = new StringBuilder();
1453 s.append("UpdateRecord[");
1454 s.append(mProvider);
1455 s.append(' ').append(mReceiver.mPackageName).append('(');
1456 s.append(mReceiver.mUid).append(')');
1457 s.append(' ').append(mRequest);
1458 s.append(']');
1459 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461 }
1462
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001463 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07001464 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001465 IBinder binder = listener.asBinder();
1466 Receiver receiver = mReceivers.get(binder);
1467 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001468 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
1469 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001470 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001471 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001472 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001473 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001474 return null;
1475 }
Wen Jingcb3ab222014-03-27 13:42:59 +08001476 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001477 }
1478 return receiver;
1479 }
1480
David Christie82edc9b2013-07-19 11:31:42 -07001481 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07001482 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001483 Receiver receiver = mReceivers.get(intent);
1484 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001485 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
1486 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001487 mReceivers.put(intent, receiver);
1488 }
1489 return receiver;
1490 }
1491
Victoria Lease37425c32012-10-16 16:08:48 -07001492 /**
1493 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1494 * and consistency requirements.
1495 *
1496 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07001497 * @return a version of request that meets the given resolution and consistency requirements
1498 * @hide
1499 */
1500 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1501 LocationRequest sanitizedRequest = new LocationRequest(request);
1502 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1503 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001504 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001505 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001506 break;
1507 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001508 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001509 break;
1510 }
1511 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001512 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1513 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001514 }
Victoria Lease37425c32012-10-16 16:08:48 -07001515 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1516 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001517 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001518 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001519 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001520 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001521 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001522 }
Victoria Lease37425c32012-10-16 16:08:48 -07001523 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001524 }
1525
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001526 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001527 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001528 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001529 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001530 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001531 String[] packages = mPackageManager.getPackagesForUid(uid);
1532 if (packages == null) {
1533 throw new SecurityException("invalid UID " + uid);
1534 }
1535 for (String pkg : packages) {
1536 if (packageName.equals(pkg)) return;
1537 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001538 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001539 }
1540
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001541 private void checkPendingIntent(PendingIntent intent) {
1542 if (intent == null) {
1543 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001544 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001545 }
1546
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001547 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
David Christie40e57822013-07-30 11:36:48 -07001548 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001549 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001550 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001551 } else if (intent != null && listener != null) {
1552 throw new IllegalArgumentException("cannot register both listener and intent");
1553 } else if (intent != null) {
1554 checkPendingIntent(intent);
David Christie40e57822013-07-30 11:36:48 -07001555 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001556 } else {
David Christie40e57822013-07-30 11:36:48 -07001557 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001558 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001559 }
1560
Nick Pellye0fd6932012-07-11 10:26:13 -07001561 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001562 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1563 PendingIntent intent, String packageName) {
1564 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1565 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001566 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1567 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1568 request.getProvider());
David Christie82edc9b2013-07-19 11:31:42 -07001569 WorkSource workSource = request.getWorkSource();
1570 if (workSource != null && workSource.size() > 0) {
David Christie40e57822013-07-30 11:36:48 -07001571 checkDeviceStatsAllowed();
1572 }
1573 boolean hideFromAppOps = request.getHideFromAppOps();
1574 if (hideFromAppOps) {
1575 checkUpdateAppOpsAllowed();
David Christie82edc9b2013-07-19 11:31:42 -07001576 }
Victoria Lease37425c32012-10-16 16:08:48 -07001577 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001578
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001579 final int pid = Binder.getCallingPid();
1580 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001581 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001582 long identity = Binder.clearCallingIdentity();
1583 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001584 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1585 // a location.
Dianne Hackborn35654b62013-01-14 17:38:02 -08001586 checkLocationAccess(uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001587
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001588 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001589 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
David Christie40e57822013-07-30 11:36:48 -07001590 packageName, workSource, hideFromAppOps);
Victoria Lease37425c32012-10-16 16:08:48 -07001591 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001592 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001593 } finally {
1594 Binder.restoreCallingIdentity(identity);
1595 }
1596 }
1597
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001598 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1599 int pid, int uid, String packageName) {
1600 // Figure out the provider. Either its explicitly request (legacy use cases), or
1601 // use the fused provider
1602 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1603 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001604 if (name == null) {
1605 throw new IllegalArgumentException("provider name must not be null");
1606 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07001607
1608 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1609 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001610 LocationProviderInterface provider = mProvidersByName.get(name);
1611 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07001612 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001613 }
1614
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001615 UpdateRecord record = new UpdateRecord(name, request, receiver);
1616 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1617 if (oldRecord != null) {
1618 oldRecord.disposeLocked(false);
1619 }
1620
Victoria Lease09eeaec2013-02-05 11:34:13 -08001621 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001622 if (isProviderEnabled) {
1623 applyRequirementsLocked(name);
1624 } else {
1625 // Notify the listener that updates are currently disabled
1626 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001627 }
David Christie0b837452013-07-29 16:02:13 -07001628 // Update the monitoring here just in case multiple location requests were added to the
1629 // same receiver (this request may be high power and the initial might not have been).
1630 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001631 }
1632
Nick Pellye0fd6932012-07-11 10:26:13 -07001633 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001634 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1635 String packageName) {
1636 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001637
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001638 final int pid = Binder.getCallingPid();
1639 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001640
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001641 synchronized (mLock) {
David Christie82edc9b2013-07-19 11:31:42 -07001642 WorkSource workSource = null;
David Christie40e57822013-07-30 11:36:48 -07001643 boolean hideFromAppOps = false;
1644 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
1645 packageName, workSource, hideFromAppOps);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001646
1647 // providers may use public location API's, need to clear identity
1648 long identity = Binder.clearCallingIdentity();
1649 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001650 removeUpdatesLocked(receiver);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001651 } finally {
1652 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001654 }
1655 }
1656
1657 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001658 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001659
1660 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1661 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1662 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001663 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001664 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001665 }
1666
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001667 receiver.updateMonitoring(false);
1668
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001669 // Record which providers were associated with this listener
1670 HashSet<String> providers = new HashSet<String>();
1671 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1672 if (oldRecords != null) {
1673 // Call dispose() on the obsolete update records.
1674 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08001675 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001676 record.disposeLocked(false);
1677 }
1678 // Accumulate providers
1679 providers.addAll(oldRecords.keySet());
1680 }
1681
1682 // update provider
1683 for (String provider : providers) {
1684 // If provider is already disabled, don't need to do anything
Victoria Lease09eeaec2013-02-05 11:34:13 -08001685 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001686 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001687 }
1688
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001689 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 }
1691 }
1692
Dianne Hackbornc2293022013-02-06 23:14:49 -08001693 private void applyAllProviderRequirementsLocked() {
1694 for (LocationProviderInterface p : mProviders) {
1695 // If provider is already disabled, don't need to do anything
Dianne Hackborn64d41d72013-02-07 00:33:31 -08001696 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08001697 continue;
1698 }
1699
1700 applyRequirementsLocked(p.getName());
1701 }
1702 }
1703
Nick Pellye0fd6932012-07-11 10:26:13 -07001704 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001705 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001706 if (D) Log.d(TAG, "getLastLocation: " + request);
1707 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001708 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001709 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001710 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1711 request.getProvider());
1712 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001713
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001714 final int uid = Binder.getCallingUid();
1715 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001716 try {
1717 if (mBlacklist.isBlacklisted(packageName)) {
1718 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1719 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001720 return null;
1721 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001722
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001723 if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
1724 if (D) Log.d(TAG, "not returning last loc for no op app: " +
1725 packageName);
1726 return null;
1727 }
1728
Victoria Leaseb711d572012-10-02 13:14:11 -07001729 synchronized (mLock) {
1730 // Figure out the provider. Either its explicitly request (deprecated API's),
1731 // or use the fused provider
1732 String name = request.getProvider();
1733 if (name == null) name = LocationManager.FUSED_PROVIDER;
1734 LocationProviderInterface provider = mProvidersByName.get(name);
1735 if (provider == null) return null;
1736
Victoria Lease09eeaec2013-02-05 11:34:13 -08001737 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001738
David Christie1b9b7b12013-04-15 15:31:11 -07001739 Location location;
1740 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1741 // Make sure that an app with coarse permissions can't get frequent location
1742 // updates by calling LocationManager.getLastKnownLocation repeatedly.
1743 location = mLastLocationCoarseInterval.get(name);
1744 } else {
1745 location = mLastLocation.get(name);
1746 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001747 if (location == null) {
1748 return null;
1749 }
Victoria Lease37425c32012-10-16 16:08:48 -07001750 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001751 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1752 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001753 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07001754 }
Victoria Lease37425c32012-10-16 16:08:48 -07001755 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001756 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07001757 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001758 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001759 return null;
1760 } finally {
1761 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001762 }
1763 }
1764
1765 @Override
1766 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1767 String packageName) {
1768 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001769 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1770 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001771 checkPendingIntent(intent);
1772 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001773 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1774 request.getProvider());
1775 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001776
Victoria Lease37425c32012-10-16 16:08:48 -07001777 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001778
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001779 // geo-fence manager uses the public location API, need to clear identity
1780 int uid = Binder.getCallingUid();
Victoria Lease56e675b2012-11-05 19:25:06 -08001781 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1782 // temporary measure until geofences work for secondary users
1783 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1784 return;
1785 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001786 long identity = Binder.clearCallingIdentity();
1787 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001788 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1789 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001790 } finally {
1791 Binder.restoreCallingIdentity(identity);
1792 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001793 }
1794
1795 @Override
1796 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease37425c32012-10-16 16:08:48 -07001797 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001798 checkPendingIntent(intent);
1799 checkPackageName(packageName);
1800
1801 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1802
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001803 // geo-fence manager uses the public location API, need to clear identity
1804 long identity = Binder.clearCallingIdentity();
1805 try {
1806 mGeofenceManager.removeFence(geofence, intent);
1807 } finally {
1808 Binder.restoreCallingIdentity(identity);
1809 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001810 }
1811
1812
1813 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001814 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001815 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1816 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001817 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001818
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001819 final int uid = Binder.getCallingUid();
1820 final long ident = Binder.clearCallingIdentity();
1821 try {
Victoria Lease3d5173d2013-02-05 16:07:32 -08001822 if (!checkLocationAccess(uid, packageName, allowedResolutionLevel)) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001823 return false;
1824 }
1825 } finally {
1826 Binder.restoreCallingIdentity(ident);
1827 }
1828
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09001829 if (mGpsStatusProvider == null) {
1830 return false;
1831 }
1832
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001833 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001834 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001835 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001836 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001837 return false;
1838 }
1839 return true;
1840 }
1841
Nick Pellye0fd6932012-07-11 10:26:13 -07001842 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001844 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001845 try {
1846 mGpsStatusProvider.removeGpsStatusListener(listener);
1847 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001848 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001849 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 }
1851 }
1852
Nick Pellye0fd6932012-07-11 10:26:13 -07001853 @Override
destradaaea8a8a62014-06-23 18:19:03 -07001854 public boolean addGpsMeasurementsListener(
1855 IGpsMeasurementsListener listener,
1856 String packageName) {
1857 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1858 checkResolutionLevelIsSufficientForProviderUse(
1859 allowedResolutionLevel,
1860 LocationManager.GPS_PROVIDER);
1861
1862 int uid = Binder.getCallingUid();
1863 long identity = Binder.clearCallingIdentity();
1864 boolean hasLocationAccess;
1865 try {
1866 hasLocationAccess = checkLocationAccess(uid, packageName, allowedResolutionLevel);
1867 } finally {
1868 Binder.restoreCallingIdentity(identity);
1869 }
1870
Wei Liu5241a4c2015-05-11 14:00:36 -07001871 if (!hasLocationAccess || mGpsMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07001872 return false;
1873 }
destradaaea8a8a62014-06-23 18:19:03 -07001874 return mGpsMeasurementsProvider.addListener(listener);
1875 }
1876
1877 @Override
destradaa6568d702014-10-27 12:47:41 -07001878 public void removeGpsMeasurementsListener(IGpsMeasurementsListener listener) {
Wei Liu5241a4c2015-05-11 14:00:36 -07001879 if (mGpsMeasurementsProvider != null) {
1880 mGpsMeasurementsProvider.removeListener(listener);
1881 }
destradaaea8a8a62014-06-23 18:19:03 -07001882 }
1883
1884 @Override
destradaa4b3e3932014-07-21 18:01:47 -07001885 public boolean addGpsNavigationMessageListener(
1886 IGpsNavigationMessageListener listener,
1887 String packageName) {
1888 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1889 checkResolutionLevelIsSufficientForProviderUse(
1890 allowedResolutionLevel,
1891 LocationManager.GPS_PROVIDER);
1892
1893 int uid = Binder.getCallingUid();
1894 long identity = Binder.clearCallingIdentity();
1895 boolean hasLocationAccess;
1896 try {
1897 hasLocationAccess = checkLocationAccess(uid, packageName, allowedResolutionLevel);
1898 } finally {
1899 Binder.restoreCallingIdentity(identity);
1900 }
1901
Wei Liu5241a4c2015-05-11 14:00:36 -07001902 if (!hasLocationAccess || mGpsNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07001903 return false;
1904 }
1905 return mGpsNavigationMessageProvider.addListener(listener);
1906 }
1907
1908 @Override
destradaa6568d702014-10-27 12:47:41 -07001909 public void removeGpsNavigationMessageListener(IGpsNavigationMessageListener listener) {
Wei Liu5241a4c2015-05-11 14:00:36 -07001910 if (mGpsNavigationMessageProvider != null) {
1911 mGpsNavigationMessageProvider.removeListener(listener);
1912 }
destradaa4b3e3932014-07-21 18:01:47 -07001913 }
1914
1915 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001916 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001917 if (provider == null) {
1918 // throw NullPointerException to remain compatible with previous implementation
1919 throw new NullPointerException();
1920 }
Victoria Lease37425c32012-10-16 16:08:48 -07001921 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1922 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001923
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001924 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001925 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001926 != PackageManager.PERMISSION_GRANTED)) {
1927 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1928 }
1929
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001930 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001931 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001932 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001933
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001934 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001935 }
1936 }
1937
Nick Pellye0fd6932012-07-11 10:26:13 -07001938 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001939 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001940 if (Binder.getCallingUid() != Process.myUid()) {
1941 throw new SecurityException(
1942 "calling sendNiResponse from outside of the system is not allowed");
1943 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001944 try {
1945 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001946 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001947 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001948 return false;
1949 }
1950 }
1951
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001952 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001953 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001954 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001955 * accessed by the caller
1956 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001957 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001958 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001959 if (mProvidersByName.get(provider) == null) {
David Christie2ff96af2014-01-30 16:09:37 -08001960 return null;
Laurent Tub7f9d252012-10-16 14:25:00 -07001961 }
1962
Victoria Lease37425c32012-10-16 16:08:48 -07001963 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1964 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001965
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001966 LocationProviderInterface p;
1967 synchronized (mLock) {
1968 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001969 }
1970
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001971 if (p == null) return null;
1972 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001973 }
1974
Nick Pellye0fd6932012-07-11 10:26:13 -07001975 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001976 public boolean isProviderEnabled(String provider) {
Tom O'Neilld5759432013-09-11 11:03:03 -07001977 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
1978 // so we discourage its use
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001979 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1980
Victoria Lease09eeaec2013-02-05 11:34:13 -08001981 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07001982 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001983 try {
1984 synchronized (mLock) {
1985 LocationProviderInterface p = mProvidersByName.get(provider);
1986 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001987
Victoria Lease09eeaec2013-02-05 11:34:13 -08001988 return isAllowedByUserSettingsLocked(provider, uid);
Victoria Leaseb711d572012-10-02 13:14:11 -07001989 }
1990 } finally {
1991 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001992 }
1993 }
1994
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001995 /**
1996 * Returns "true" if the UID belongs to a bound location provider.
1997 *
1998 * @param uid the uid
1999 * @return true if uid belongs to a bound location provider
2000 */
2001 private boolean isUidALocationProvider(int uid) {
2002 if (uid == Process.SYSTEM_UID) {
2003 return true;
2004 }
2005 if (mGeocodeProvider != null) {
David Christie1f141c12014-05-14 15:11:15 -07002006 if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002007 }
2008 for (LocationProviderProxy proxy : mProxyProviders) {
David Christie1f141c12014-05-14 15:11:15 -07002009 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002010 }
2011 return false;
2012 }
2013
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002014 private void checkCallerIsProvider() {
2015 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
2016 == PackageManager.PERMISSION_GRANTED) {
2017 return;
2018 }
2019
2020 // Previously we only used the INSTALL_LOCATION_PROVIDER
2021 // check. But that is system or signature
2022 // protection level which is not flexible enough for
2023 // providers installed oustide the system image. So
2024 // also allow providers with a UID matching the
2025 // currently bound package name
2026
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002027 if (isUidALocationProvider(Binder.getCallingUid())) {
2028 return;
2029 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002030
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002031 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2032 "or UID of a currently bound location provider");
2033 }
2034
David Christie1f141c12014-05-14 15:11:15 -07002035 /**
2036 * Returns true if the given package belongs to the given uid.
2037 */
2038 private boolean doesUidHavePackage(int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002039 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002040 return false;
2041 }
David Christie1f141c12014-05-14 15:11:15 -07002042 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2043 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002044 return false;
2045 }
David Christie1f141c12014-05-14 15:11:15 -07002046 for (String name : packageNames) {
2047 if (packageName.equals(name)) {
2048 return true;
2049 }
2050 }
2051 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002052 }
2053
Nick Pellye0fd6932012-07-11 10:26:13 -07002054 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05002055 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002056 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04002057
Nick Pelly2eeeec22012-07-18 13:13:37 -07002058 if (!location.isComplete()) {
2059 Log.w(TAG, "Dropping incomplete location: " + location);
2060 return;
2061 }
2062
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002063 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2064 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05002065 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002066 mLocationHandler.sendMessageAtFrontOfQueue(m);
2067 }
2068
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002069
Laurent Tu75defb62012-11-01 16:21:52 -07002070 private static boolean shouldBroadcastSafe(
2071 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002072 // Always broadcast the first update
2073 if (lastLoc == null) {
2074 return true;
2075 }
2076
Nick Pellyf1be6862012-05-15 10:53:42 -07002077 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002078 long minTime = record.mRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002079 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2080 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002081 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002082 return false;
2083 }
2084
2085 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002086 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002087 if (minDistance > 0.0) {
2088 if (loc.distanceTo(lastLoc) <= minDistance) {
2089 return false;
2090 }
2091 }
2092
Laurent Tu75defb62012-11-01 16:21:52 -07002093 // Check whether sufficient number of udpates is left
2094 if (record.mRequest.getNumUpdates() <= 0) {
2095 return false;
2096 }
2097
2098 // Check whether the expiry date has passed
2099 if (record.mRequest.getExpireAt() < now) {
2100 return false;
2101 }
2102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002103 return true;
2104 }
2105
Mike Lockwooda4903f22010-02-17 06:42:23 -05002106 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002107 if (D) Log.d(TAG, "incoming location: " + location);
2108
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002109 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05002110 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002111
Laurent Tu60ec50a2012-10-04 17:00:10 -07002112 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002113 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002114 if (p == null) return;
2115
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002116 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07002117 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2118 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002119 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002120 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002121 lastLocation = new Location(provider);
2122 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07002123 } else {
2124 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2125 if (noGPSLocation == null && lastNoGPSLocation != null) {
2126 // New location has no no-GPS location: adopt last no-GPS location. This is set
2127 // directly into location because we do not want to notify COARSE clients.
2128 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
2129 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07002130 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002131 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002132
David Christie1b9b7b12013-04-15 15:31:11 -07002133 // Update last known coarse interval location if enough time has passed.
2134 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2135 if (lastLocationCoarseInterval == null) {
2136 lastLocationCoarseInterval = new Location(location);
2137 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2138 }
2139 long timeDiffNanos = location.getElapsedRealtimeNanos()
2140 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2141 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
2142 lastLocationCoarseInterval.set(location);
2143 }
2144 // Don't ever return a coarse location that is more recent than the allowed update
2145 // interval (i.e. don't allow an app to keep registering and unregistering for
2146 // location updates to overcome the minimum interval).
2147 noGPSLocation =
2148 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2149
Laurent Tu60ec50a2012-10-04 17:00:10 -07002150 // Skip if there are no UpdateRecords for this provider.
2151 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2152 if (records == null || records.size() == 0) return;
2153
Victoria Lease09016ab2012-09-16 12:33:15 -07002154 // Fetch coarse location
2155 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07002156 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002157 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2158 }
2159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002160 // Fetch latest status update time
2161 long newStatusUpdateTime = p.getStatusUpdateTime();
2162
David Christie2ff96af2014-01-30 16:09:37 -08002163 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002164 Bundle extras = new Bundle();
2165 int status = p.getStatus(extras);
2166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002167 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002168 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07002169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002170 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002171 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002172 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07002173 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07002174
Victoria Lease269518e2012-10-29 08:25:39 -07002175 int receiverUserId = UserHandle.getUserId(receiver.mUid);
Amith Yamasanib27528d2014-06-05 15:02:10 -07002176 if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07002177 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07002178 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07002179 " (current user: " + mCurrentUserId + ", app: " +
2180 receiver.mPackageName + ")");
2181 }
2182 continue;
2183 }
2184
Nick Pelly4035f5a2012-08-17 14:43:49 -07002185 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
2186 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
2187 receiver.mPackageName);
2188 continue;
2189 }
2190
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002191 if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
2192 receiver.mAllowedResolutionLevel)) {
2193 if (D) Log.d(TAG, "skipping loc update for no op app: " +
2194 receiver.mPackageName);
2195 continue;
2196 }
2197
Victoria Lease09016ab2012-09-16 12:33:15 -07002198 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07002199 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2200 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002201 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07002202 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002203 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002204 if (notifyLocation != null) {
2205 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07002206 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002207 if (lastLoc == null) {
2208 lastLoc = new Location(notifyLocation);
2209 r.mLastFixBroadcast = lastLoc;
2210 } else {
2211 lastLoc.set(notifyLocation);
2212 }
2213 if (!receiver.callLocationChangedLocked(notifyLocation)) {
2214 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2215 receiverDead = true;
2216 }
Laurent Tu75defb62012-11-01 16:21:52 -07002217 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002218 }
2219 }
2220
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002221 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002222 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07002223 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002224
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002225 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002226 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002227 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08002228 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07002229 }
2230 }
2231
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002232 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07002233 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002234 if (deadUpdateRecords == null) {
2235 deadUpdateRecords = new ArrayList<UpdateRecord>();
2236 }
2237 deadUpdateRecords.add(r);
2238 }
2239 // track dead receivers
2240 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002241 if (deadReceivers == null) {
2242 deadReceivers = new ArrayList<Receiver>();
2243 }
2244 if (!deadReceivers.contains(receiver)) {
2245 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002246 }
2247 }
2248 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002249
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002250 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002251 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002252 for (Receiver receiver : deadReceivers) {
2253 removeUpdatesLocked(receiver);
2254 }
2255 }
2256 if (deadUpdateRecords != null) {
2257 for (UpdateRecord r : deadUpdateRecords) {
2258 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002259 }
Victoria Lease8b38b292012-12-04 15:04:43 -08002260 applyRequirementsLocked(provider);
2261 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002262 }
2263
2264 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08002265 public LocationWorkerHandler(Looper looper) {
2266 super(looper, null, true);
2267 }
2268
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002269 @Override
2270 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002271 switch (msg.what) {
2272 case MSG_LOCATION_CHANGED:
2273 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
2274 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002275 }
2276 }
2277 }
2278
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002279 private boolean isMockProvider(String provider) {
2280 synchronized (mLock) {
2281 return mMockProviders.containsKey(provider);
2282 }
2283 }
2284
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002285 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002286 // create a working copy of the incoming Location so that the service can modify it without
2287 // disturbing the caller's copy
2288 Location myLocation = new Location(location);
2289 String provider = myLocation.getProvider();
2290
2291 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2292 // bit if location did not come from a mock provider because passive/fused providers can
2293 // forward locations from mock providers, and should not grant them legitimacy in doing so.
2294 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
2295 myLocation.setIsFromMockProvider(true);
2296 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08002297
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002298 synchronized (mLock) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08002299 if (isAllowedByCurrentUserSettingsLocked(provider)) {
2300 if (!passive) {
2301 // notify passive provider of the new location
2302 mPassiveProvider.updateLocation(myLocation);
2303 }
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002304 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002305 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002306 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002307 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002308
Mike Lockwoode97ae402010-09-29 15:23:46 -04002309 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2310 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002311 public void onPackageDisappeared(String packageName, int reason) {
2312 // remove all receivers associated with this package name
2313 synchronized (mLock) {
2314 ArrayList<Receiver> deadReceivers = null;
2315
2316 for (Receiver receiver : mReceivers.values()) {
2317 if (receiver.mPackageName.equals(packageName)) {
2318 if (deadReceivers == null) {
2319 deadReceivers = new ArrayList<Receiver>();
2320 }
2321 deadReceivers.add(receiver);
2322 }
2323 }
2324
2325 // perform removal outside of mReceivers loop
2326 if (deadReceivers != null) {
2327 for (Receiver receiver : deadReceivers) {
2328 removeUpdatesLocked(receiver);
2329 }
2330 }
2331 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002332 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04002333 };
2334
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002335 // Geocoder
2336
Nick Pellye0fd6932012-07-11 10:26:13 -07002337 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04002338 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07002339 return mGeocodeProvider != null;
2340 }
2341
Nick Pellye0fd6932012-07-11 10:26:13 -07002342 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002343 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002344 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002345 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002346 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2347 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002348 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002349 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002350 }
2351
Mike Lockwooda55c3212009-04-15 11:10:11 -04002352
Nick Pellye0fd6932012-07-11 10:26:13 -07002353 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002354 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04002355 double lowerLeftLatitude, double lowerLeftLongitude,
2356 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002357 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002358
2359 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002360 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2361 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2362 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002363 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002364 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002365 }
2366
2367 // Mock Providers
2368
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002369 private boolean canCallerAccessMockLocation(String opPackageName) {
2370 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
2371 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002372 }
2373
Nick Pellye0fd6932012-07-11 10:26:13 -07002374 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002375 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
2376 if (!canCallerAccessMockLocation(opPackageName)) {
2377 return;
2378 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002379
Mike Lockwooda4903f22010-02-17 06:42:23 -05002380 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2381 throw new IllegalArgumentException("Cannot mock the passive location provider");
2382 }
2383
Mike Lockwood86328a92009-10-23 08:38:25 -04002384 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002385 synchronized (mLock) {
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002386 // remove the real provider if we are replacing GPS or network provider
2387 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07002388 || LocationManager.NETWORK_PROVIDER.equals(name)
2389 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002390 LocationProviderInterface p = mProvidersByName.get(name);
2391 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002392 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002393 }
2394 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09002395 addTestProviderLocked(name, properties);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002396 updateProvidersLocked();
2397 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002398 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002399 }
2400
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09002401 private void addTestProviderLocked(String name, ProviderProperties properties) {
2402 if (mProvidersByName.get(name) != null) {
2403 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2404 }
2405 MockProvider provider = new MockProvider(name, this, properties);
2406 addProviderLocked(provider);
2407 mMockProviders.put(name, provider);
2408 mLastLocation.put(name, null);
2409 mLastLocationCoarseInterval.put(name, null);
2410 }
2411
Nick Pellye0fd6932012-07-11 10:26:13 -07002412 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002413 public void removeTestProvider(String provider, String opPackageName) {
2414 if (!canCallerAccessMockLocation(opPackageName)) {
2415 return;
2416 }
2417
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002418 synchronized (mLock) {
Tom O'Neill07ee5d12014-03-03 17:48:35 -08002419
2420 // These methods can't be called after removing the test provider, so first make sure
Tom O'Neillfe6d3c52014-03-04 08:26:17 -08002421 // we don't leave anything dangling.
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002422 clearTestProviderEnabled(provider, opPackageName);
2423 clearTestProviderLocation(provider, opPackageName);
2424 clearTestProviderStatus(provider, opPackageName);
Tom O'Neill07ee5d12014-03-03 17:48:35 -08002425
You Kima6d0b6f2012-10-28 03:58:44 +09002426 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002427 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002428 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2429 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002430 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002431 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002432
2433 // reinstate real provider if available
2434 LocationProviderInterface realProvider = mRealProviders.get(provider);
2435 if (realProvider != null) {
2436 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002437 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002438 mLastLocation.put(provider, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002439 mLastLocationCoarseInterval.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002440 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002441 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002442 }
2443 }
2444
Nick Pellye0fd6932012-07-11 10:26:13 -07002445 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002446 public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
2447 if (!canCallerAccessMockLocation(opPackageName)) {
2448 return;
2449 }
2450
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002451 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002452 MockProvider mockProvider = mMockProviders.get(provider);
2453 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002454 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2455 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04002456 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2457 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002458 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04002459 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002460 }
2461 }
2462
Nick Pellye0fd6932012-07-11 10:26:13 -07002463 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002464 public void clearTestProviderLocation(String provider, String opPackageName) {
2465 if (!canCallerAccessMockLocation(opPackageName)) {
2466 return;
2467 }
2468
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002469 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002470 MockProvider mockProvider = mMockProviders.get(provider);
2471 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002472 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2473 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002474 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002475 }
2476 }
2477
Nick Pellye0fd6932012-07-11 10:26:13 -07002478 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002479 public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
2480 if (!canCallerAccessMockLocation(opPackageName)) {
2481 return;
2482 }
2483
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002484 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002485 MockProvider mockProvider = mMockProviders.get(provider);
2486 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002487 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2488 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002489 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002490 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002491 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002492 mEnabledProviders.add(provider);
2493 mDisabledProviders.remove(provider);
2494 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002495 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002496 mEnabledProviders.remove(provider);
2497 mDisabledProviders.add(provider);
2498 }
2499 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002500 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002501 }
2502 }
2503
Nick Pellye0fd6932012-07-11 10:26:13 -07002504 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002505 public void clearTestProviderEnabled(String provider, String opPackageName) {
2506 if (!canCallerAccessMockLocation(opPackageName)) {
2507 return;
2508 }
2509
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002510 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002511 MockProvider mockProvider = mMockProviders.get(provider);
2512 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002513 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2514 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002515 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002516 mEnabledProviders.remove(provider);
2517 mDisabledProviders.remove(provider);
2518 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002519 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002520 }
2521 }
2522
Nick Pellye0fd6932012-07-11 10:26:13 -07002523 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002524 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
2525 String opPackageName) {
2526 if (!canCallerAccessMockLocation(opPackageName)) {
2527 return;
2528 }
2529
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002530 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002531 MockProvider mockProvider = mMockProviders.get(provider);
2532 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002533 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2534 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002535 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002536 }
2537 }
2538
Nick Pellye0fd6932012-07-11 10:26:13 -07002539 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002540 public void clearTestProviderStatus(String provider, String opPackageName) {
2541 if (!canCallerAccessMockLocation(opPackageName)) {
2542 return;
2543 }
2544
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002545 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002546 MockProvider mockProvider = mMockProviders.get(provider);
2547 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002548 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2549 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002550 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002551 }
2552 }
2553
2554 private void log(String log) {
2555 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002556 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002557 }
2558 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002559
2560 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002561 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2562 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2563 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002564 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002565 + Binder.getCallingPid()
2566 + ", uid=" + Binder.getCallingUid());
2567 return;
2568 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002569
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002570 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002571 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002572 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002573 for (Receiver receiver : mReceivers.values()) {
2574 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002575 }
David Christie2ff96af2014-01-30 16:09:37 -08002576 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002577 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2578 pw.println(" " + entry.getKey() + ":");
2579 for (UpdateRecord record : entry.getValue()) {
2580 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002581 }
2582 }
David Christie2ff96af2014-01-30 16:09:37 -08002583 pw.println(" Historical Records by Provider:");
2584 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
2585 : mRequestStatistics.statistics.entrySet()) {
2586 PackageProviderKey key = entry.getKey();
2587 PackageStatistics stats = entry.getValue();
2588 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
2589 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002590 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002591 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2592 String provider = entry.getKey();
2593 Location location = entry.getValue();
2594 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002595 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002596
David Christie1b9b7b12013-04-15 15:31:11 -07002597 pw.println(" Last Known Locations Coarse Intervals:");
2598 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2599 String provider = entry.getKey();
2600 Location location = entry.getValue();
2601 pw.println(" " + provider + ": " + location);
2602 }
2603
Nick Pellye0fd6932012-07-11 10:26:13 -07002604 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002605
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002606 if (mEnabledProviders.size() > 0) {
2607 pw.println(" Enabled Providers:");
2608 for (String i : mEnabledProviders) {
2609 pw.println(" " + i);
2610 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002612 }
2613 if (mDisabledProviders.size() > 0) {
2614 pw.println(" Disabled Providers:");
2615 for (String i : mDisabledProviders) {
2616 pw.println(" " + i);
2617 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002618 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002619 pw.append(" ");
2620 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002621 if (mMockProviders.size() > 0) {
2622 pw.println(" Mock Providers:");
2623 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002624 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002625 }
2626 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002627
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002628 pw.append(" fudger: ");
2629 mLocationFudger.dump(fd, pw, args);
2630
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002631 if (args.length > 0 && "short".equals(args[0])) {
2632 return;
2633 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002634 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002635 pw.print(provider.getName() + " Internal State");
2636 if (provider instanceof LocationProviderProxy) {
2637 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2638 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002639 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002640 pw.println(":");
2641 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002642 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002643 }
2644 }
2645}